데이터 구조 12주차: (방향 비순환 그래프의 위상 정렬 + 위상 정렬 및 중요 경로 + 경쟁 순위 결정 + 컷 포인트)

방향성 비순환 그래프의 토폴로지 정렬

【문제 설명】

해당 세트의 부분 순서에서 세트의 전체 순서를 얻는 것을 토폴로지 정렬이라고 합니다. 부분 순서 및 전체 순서의 정의는 다음과 같습니다. 집합 X의 관계 R이 반사적, 반대칭 및 전이적이면 R은 집합 X의 부분 순서 관계라고 합니다. R을 집합 X에 대한 부분 차수라고 하고, 각 x, y∈X에 대해 xRy 또는 yRx가 있어야 한다면 R은 집합 X에 대한 전체 차수라고 합니다. 부분 순서의 정의로 위상 순서를 구하는 작업을 위상 정렬이라고 합니다.

토폴로지 정렬 프로세스는 다음과 같습니다.

  1. 유방향 그래프에서 선행자가 없는 정점을 선택하고 출력합니다.

  2. 그래프에서 이 꼭지점과 꼭지점에서 이어지는 모든 호를 제거합니다.

모든 정점이 출력될 때까지 또는 현재 그래프에 선행 정점이 없는 정점이 없을 때까지 위의 두 단계를 반복합니다. 후자의 경우는 유향 그래프에 주기가 있음을 나타냅니다.
이 문제에서는 유향 그래프(즉, 배열 표현)의 인접 행렬을 읽어서 유향 그래프를 만들고 위에서 설명한 알고리즘에 따라 그래프에 루프가 있는지 판단하고 위상적으로 정렬된 정점 시퀀스가 ​​있으면 출력합니다. 루프가 없습니다.

【입력 양식】

입력의 첫 번째 줄에는 그래프에 n개의 정점이 있음을 나타내는 양의 정수 n이 포함됩니다. 여기서 n은 50을 초과하지 않습니다.

다음 n개의 줄 각각에는 공백으로 구분된 n개의 정수 0 또는 1이 있습니다. -번째 정점 , 0은 i에서 j로 향하는 가장자리가 없음을 의미합니다. i와 j가 같을 때 해당 정수는 0이 보장됩니다.

【출력 형식】

방향 그래프 읽기에 주기가 포함되어 있으면 따옴표 없이 "ERROR"를 출력합니다.

읽어온 방향성 그래프에 루프가 포함되어 있지 않으면 항목 설명의 알고리즘에 따라 그래프의 토폴로지 순서를 차례로 출력하고 각 정수 뒤에 공백을 출력하십시오.

줄 끝에 있는 개행 출력에 유의하십시오.

【샘플 입력】

4
0 1 0 0 0
0 1
0 0
0 0 0 0 0 1 0
【샘플 출력】

3 0 1 2

[설명] 인접 리스트 저장 구조를 사용할 때 연결 리스트의 생성은 후속 노드가 작은 것부터 큰 것까지 배열되도록 꼬리 삽입 방식을 사용해야 합니다.

이 질문에서는 제목 설명에 있는 알고리즘에 따라 엄격하게 위상 정렬을 수행하고 정렬 과정에서 꼭짓점을 순서대로 저장해야 하며 유향 그래프에 포함되지 않은 것으로 최종 결정될 때까지 출력을 수행할 수 없습니다. 루프.

또한, 도수가 0인 꼭지점의 반복적인 검출을 피하기 위해 스택 구조를 사용하여 현재 처리 프로세스에서 도수가 0인 꼭지점을 유지하도록 할 수 있습니다.

#include<iostream>
#include<stdlib.h>
#include<stack>
#define N 50
using namespace std;

typedef struct node
{
    
    
    int data;
    struct node * next;
}ArcNode;

typedef struct
{
    
    
    int in; //表示该节点的入度
    int vertex; // 该节点的信息
    int flag; //判断该节点是否入栈的标志
    ArcNode * firstedge;
}ALGraph;

ALGraph G[N];
int res[N];

void TopoSort(int limit)
{
    
    
    stack<ALGraph*> s;
    int count = 0;
    int i = 0;
    for(i = 0; i < limit; i ++)
    {
    
    
        if(G[i].in == 0)
        {
    
    
            s.push(&G[i]);
            G[i].flag = 0;
        }
    }
    while(!s.empty())
    {
    
    
        ALGraph * pos = s.top();
        s.pop();
        count ++;
        res[count] = pos->vertex;
        ArcNode * p = pos->firstedge;
        while(p != NULL)
        {
    
    
            int num = p->data;
            G[num].in --;
            p = p->next;
        }
        for(i = 0 ; i <limit; i ++)
        {
    
    
            if(G[i].in == 0 && G[i].flag == 1)
            {
    
    
                s.push(&G[i]);
                G[i].flag = 0;
            }
        }
    }
    if(count == limit)
    {
    
    
        for(i = 1; i <= limit; i ++)
        {
    
    
            cout<<res[i]<<" ";
        }
    }
    else
    {
    
    
        cout<<"ERROR";
    }
}

int main()
{
    
    
    int NodeNum = 0;
    cin>>NodeNum;
    int i = 0;
    int j = 0;
    for(i = 0; i < NodeNum; i ++) //邻接表初始化
    {
    
    
        G[i].in = 0;
        G[i].vertex = i;
        G[i].flag = 1;
        G[i].firstedge = NULL;
    }
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        for(j = 0; j < NodeNum; j ++)
        {
    
    
            int num;
            cin>>num;
            if(num == 0) continue;
            else
            {
    
    
                ArcNode * temp = (ArcNode*)malloc(sizeof(ArcNode));
                temp->data = j;
                temp->next = NULL;
                ArcNode * pos = G[i].firstedge;
                while(1)
                {
    
    
                    if(pos == NULL) break;
                    if(pos->next == NULL) break;
                    else
                        pos = pos->next;
                }
                if(pos == NULL)
                {
    
    
                    G[i].firstedge = temp;
                }
                else
                {
    
    
                    pos->next = temp;
                }
                G[j].in ++;
            }
        }
    }
    TopoSort(NodeNum);
    return 0;
}

토폴로지 정렬 및 중요 경로

[문제 설명] 가중 유방향 그래프에서 이벤트는 꼭지점으로, 활동은 유향 에지로, 에지의 가중치는 활동 비용(예: 활동 기간)을 나타내는 경우 이 가중 방향 그래프는 그래프 유향 그래프는 AOE 네트워크라고 합니다. AOE 네트워크가 프로젝트를 나타내는 데 사용되는 경우 다양한 하위 프로젝트 간의 우선 순위 관계를 고려하는 것만으로는 충분하지 않으며 전체 프로젝트 완료를 위한 최단 시간에 더 많은 관심을 기울입니다. 전체 프로젝트의 진행 상황 및 이러한 활동을 가속화하면 전체 프로젝트의 효율성이 향상되는지 여부. 따라서 예정된 프로젝트 계획을 완료하는 데 필요한 활동은 일반적으로 AOE 네트워크, 각 활동 계획이 완료되는 시간, 발생할 이벤트, 이러한 이벤트와 활동 간의 관계에 나열되어 프로젝트가 완료되었는지 여부를 결정합니다. 프로젝트가 완료될 시기를 예측하고 어떤 활동이 프로젝트 일정의 핵심인지 식별합니다.
[입력형식] 첫 번째 줄에 꼭짓점 수와 모서리 수를 나타내는 두 개의 숫자를 입력하고, 두 번째 줄부터 모서리 정보를 (i, j, weight) 형식으로 입력 [출력형식] 핵심 경로의 총 시간
( 최대 경로 길이), 주요 활동 에지를 나타내는 형식은 (꼭지점 1, 꼭지점 2) 크기 순서로 정렬됨
[샘플 입력]
6 8
0 1 3
0 2 2
1 3 2
1 4 3
2 3 4
2 5
3 3 5
2 4 5 1
【샘플 출력】

8

0 2

2 3

3 5

#include<iostream>
#define N 50
#include<stack>
#include<stdlib.h>
using namespace std;

typedef struct node
{
    
    
    int NodeId;
    int weight;
    int edgeId;
    struct node * next;
}ArcNode; //邻接结点结构体

typedef struct
{
    
    
    int in;
    int out;
    int flag;
    int vertex;
    ArcNode * firstedge;
}ALGraph; //邻接表结构体

ALGraph G[N];
int Relation[N][N];
int VE[N];
int VL[N];
int EE[N];
typedef struct
{
    
    
    int Weight;
    int node1;
    int node2;
}point;
point EL[N];
int el[N];
int count = -1;

void MaxPathLen(int limit)
{
    
    
    int i = 0;
    stack<ALGraph*> S;

    //用入度来处理正向拓扑排序(填充VE
    for(i = 0; i < limit; i ++)
    {
    
    
        if(G[i].in == 0)
        {
    
    
            S.push(&G[i]);
            G[i].flag = 0;
        }
    }
    while(!S.empty())
    {
    
    
        ALGraph * temp = S.top();
        S.pop();
        ArcNode * p = temp->firstedge;
        while(p != NULL) //弹出的节点的相邻节点的入度减一,填充VE
        {
    
    
            G[p->NodeId].in --;
            if(VE[temp->vertex] + p->weight > VE[p->NodeId])
            {
    
    
                VE[p->NodeId] = VE[temp->vertex] + p->weight;
                //cout<<p->NodeId<<" "<<VE[p->NodeId]<<endl;
            }
            p = p->next;
        }
        for(i = 0; i < limit; i ++)
        {
    
    
            if(G[i].in == 0 && G[i].flag == 1)
            {
    
    
                S.push(&G[i]);
                G[i].flag = 0;
            }
        }
    }
    for(i = 0; i < limit; i ++)
    {
    
    
        G[i].flag = 1; //将标记初始化
    }
    int max = -1;
    int maxid = 0;
    for(i = 0; i < limit; i ++)
    {
    
    
        if(VE[i] > max)
        {
    
    
            max = VE[i];
            maxid = i;
        }
    }
    VL[maxid] = max;

    //用出度来处理逆向拓扑排序(填充VL
    for(i = 0; i < limit; i ++)
    {
    
    
        if(G[i].out == 0)
        {
    
    
            S.push(&G[i]);
            G[i].flag = 0;
        }
    }
    while(!S.empty())
    {
    
    
        ALGraph * temp = S.top();
        S.pop();
        for(i = 0; i < limit; i ++)
        {
    
    
            if(Relation[temp->vertex][i] == 1)
            {
    
    
                G[i].out --;
                Relation[temp->vertex][i] = 0;
                ArcNode * pos = G[i].firstedge;
                while(pos->NodeId != temp->vertex) pos = pos->next;
                if(VL[i] == 0)
                {
    
    
                    VL[i] = VL[temp->vertex] - pos->weight;
                }
                if(VL[temp->vertex] - pos->weight < VL[i] )
                {
    
    
                    VL[i] = VL[temp->vertex] - pos->weight;
                    //cout<<temp->vertex<<" "<<VL[temp->vertex]<<" "<<pos->weight<<endl;
                }
            }
        }
        for(i = 0; i < limit; i ++)
        {
    
    
            if(G[i].out == 0 && G[i].flag == 1)
            {
    
    
                S.push(&G[i]);
                G[i].flag = 0;
            }
        }
    }

    //计算EE[N],EL[N]
    for(i = 0; i <= count; i ++)
    {
    
    
        int e = EE[i];
        int l = EL[i].node2;
        EE[i] = VE[e];
        el[i] = VL[l] - EL[i].Weight;
    }
    cout<<max<<endl;
    for(i = 0; i <= count; i ++)
    {
    
    
        if(EE[i] == el[i])
            cout<<EL[i].node1<<" "<<EL[i].node2<<endl;
    }
}

int main()
{
    
    
    int NodeNum;
    int EdgeNum;
    cin>>NodeNum>>EdgeNum;
    int i, j;
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        VE[i] = 0;
        VL[i] = 0;
    }
    for(i = 0; i < EdgeNum; i ++)
    {
    
    
        EE[i] = 0;
        el[i] = 0;
        EL[i].Weight = 0;
        EL[i].node1 = 0;
        EL[i].node2 = 0;
    }
    for(i = 0; i < NodeNum; i ++) //表的初始化
    {
    
    
        G[i].in = 0;
        G[i].out = 0;
        G[i].flag = 1;
        G[i].vertex = i;
        G[i].firstedge = NULL;
    }
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        for(j = 0; j < NodeNum; j ++)
        {
    
    
            Relation[i][j] = 0;
        }
    }
    i = EdgeNum;
    while(i --) //表的填充
    {
    
    
        int node1;
        int node2;
        int w;
        cin>>node1>>node2>>w;
        Relation[node2][node1] = 1;
        ArcNode * temp = (ArcNode *)malloc(sizeof(ArcNode));
        temp->NodeId = node2;
        temp->weight = w;
        temp->next = NULL;
        count ++;
        EE[count] = node1;
        EL[count].node1 = node1;
        EL[count].node2 = node2;
        EL[count].Weight = w;
        temp->edgeId = count;
        G[node1].out ++;
        G[node2].in ++;
        ArcNode * pos = G[node1].firstedge;
        if(pos == NULL)
        {
    
    
            G[node1].firstedge = temp;
        }
        else
        {
    
    
            while(1)
            {
    
    
                if(pos->next == NULL) break;
                else
                    pos = pos->next;
            }
            pos->next = temp;
        }
    }
    MaxPathLen(NodeNum);

    return 0;
}

대회 순위 결정

【문제 설명】

이 질문은 ACM 대회의 실제 질문입니다.더 강력한 테스트 데이터를 보려면 다음 링크로 이동하여 검증을 위해 코드를 제출하십시오. 문제 - 1285(hdu.edu.cn)

N개의 경쟁 팀(1<=N<=500)이 있으며 숫자는 1, 2, 3입니다. . . . , N 게임을 한다. 경기가 끝나면 심판위는 참가한 모든 팀을 앞에서 뒤로 순위를 매기는데 지금은 심판위가 각 팀의 경기 결과를 직접 입수할 수 없고 각 경기의 결과만 알며, 즉, P1이 P2를 이기고 P1을 사용하면 P2는 P1이 P2보다 순위를 매길 때 앞서 있음을 의미합니다. 이제 순위를 결정하는 프로그램을 작성하십시오.

【입력 양식】

여러 입력 그룹이 있으며 각 그룹의 첫 번째 줄은 두 개의 숫자 N(1<=N<=500), M입니다. 다음 M 행의 데이터에서 각 행에는 두 개의 정수 P1도 있습니다. P2는 P1 팀이 P2 팀을 이겼다는 것을 의미합니다.

【출력 형식】

요구 사항을 충족하는 순위를 부여하십시오. 출력시 팀 번호 사이에 공백이 있고 마지막 번호 이후에는 공백이 없습니다.

【샘플 입력】

4 3

1 2

2 3

4 3

【샘플 출력】

1 2 4 3

【예시 설명】

예선 순위가 유일한 것은 아닐 수 있습니다.이 때 숫자가 낮은 팀이 먼저 출력되어야 하며 입력 데이터는 정확함을 보장합니다. 요구 사항을 충족합니다.

#include<iostream>
#define N 50
#include<stdlib.h>
#include<stack>
using namespace std;

typedef struct node
{
    
    
    int nodeId;
    struct node * next;
}ArcNode;

typedef struct
{
    
    
    int in;
    int flag;
    int advtex;
    ArcNode * firstedge;
}ALGraph;

ALGraph G[N];

int main()
{
    
    
    int NodeNum;
    int EdgeNum;
    cin>>NodeNum>>EdgeNum;
    int i = 0;
    for(i = 1; i <= NodeNum; i ++)
    {
    
    
        G[i].advtex = i;
        G[i].in = 0;
        G[i].flag = 1;
        G[i].firstedge = NULL;
    }
    i = EdgeNum;
    while(i --)
    {
    
    
        int node1;
        int node2;
        cin>>node1>>node2;
        G[node1].advtex = node1;
        G[node2].in ++;
        ArcNode * pos = G[node1].firstedge;
        ArcNode * temp = (ArcNode*)malloc(sizeof(ArcNode));
        temp->nodeId = node2;
        temp->next = NULL;
        if(pos == NULL)
            G[node1].firstedge = temp;
        else
        {
    
    
            while(1)
            {
    
    
                if(pos->next == NULL)
                    break;
                else
                    pos = pos->next;
            }
            pos->next = temp;
        }
    }
    stack<ALGraph*> S;
    for(i = 1; i <= NodeNum; i ++)
    {
    
    
        if(G[i].in == 0)
        {
    
    
            S.push(&G[i]);
            G[i].flag = 0;
            break;
        }
    }
    while(!S.empty())
    {
    
    
        ALGraph * p = S.top();
        S.pop();
        cout<<p->advtex<<" ";
        ArcNode * pos = p->firstedge;
        while(pos != NULL)
        {
    
    
            G[pos->nodeId].in --;
            pos = pos->next;
        }
        for(i = 1; i <= NodeNum; i ++)
        {
    
    
            if(G[i].in == 0 && G[i].flag == 1)
            {
    
    
                S.push(&G[i]);
                G[i].flag = 0;
                break;
            }
        }
    }
    return 0;
}

할인

【문제 설명】

무방향 연결 그래프의 절단점을 찾습니다. 절단점의 정의는 다음과 같습니다. 이 노드와 관련 가장자리가 삭제되면 무방향 그래프는 더 이상 연결되지 않습니다.

ACM 대회에서는 연결부품, 컷포인트, 컷엣지, 수축포인트 등 Knowledge Point와 관련된 질문이 몇 가지 있는데, 이 질문을 완료한 후 다음 링크로 이동하여 유사한 질문을 보고 생각하고 제출할 수 있습니다. 스스로 코드를 확인하십시오. 문제 - 4587(hdu.edu.cn)

【입력 양식】

첫 번째 줄은 꼭지점의 수와 가장자리의 수이며, 각 후속 줄은 각 가장자리의 두 끝과 연결된 두 꼭지점입니다.

【출력 형식】

절단점, 절단점이 없으면 출력 NO

【샘플 입력】

7 8

AB

기원 후

기원전

CD

CG

DF

EF

【샘플 출력】

CD

【샘플 입력】

5 7

AB

기원전

BD

기원 후

CD

EC

【샘플 출력】

아니요

#include<iostream>
#define N 50
using namespace std;

int R[N][N];
int Dfn[N];
int Low[N];
int root = 0;
bool res[N];
int timestamp = 0;
int NodeNum; //节点个数
int RelationNum; //边的条数

void Tarjan(int p)
{
    
    
    Dfn[p] = Low[p] = ++ timestamp;
    int i = 0;
    int cnt = 0;
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        if(R[p][i] == 1)
        {
    
    
            if(Dfn[i] == 0)
            {
    
    
                Tarjan(i);
                Low[p] = min(Low[p], Low[i]);
                if(Dfn[p] <= Low[i])
                {
    
    
                    cnt ++;
                    if(p != root || cnt >= 2)
                    {
    
    
                        res[p] = 1;
                    }
                }
            }
            else
                Low[p] = min(Low[p], Dfn[i]);
        }
    }
}

int main()
{
    
    
    cin>>NodeNum>>RelationNum;

    int i, j;
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        for(j = 0; j < NodeNum; j ++)
        {
    
    
            R[i][j] = 0;
        }
    }

    i = RelationNum;
    while(i --)
    {
    
    
        char node1;
        char node2;
        cin>>node1>>node2;
        int n1 = int(node1) - 65;
        int n2 = int(node2) - 65;
        R[n1][n2] = R[n2][n1] = 1;
    }

    for(root = 0; root < NodeNum; root ++)
    {
    
    
        if(Dfn[root] == 0) Tarjan(root);
    }
    bool IsGe = false;
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        if(res[i])
        {
    
       cout<<char(i + 'A')<<" ";
            IsGe = true;
        }
    }
    if(IsGe == false) cout<<"NO";

    return 0;
}

추천

출처blog.csdn.net/qq_51800570/article/details/129178814