拓扑排序

给定一个有向图G,对于任意一条有向边<Vi,Vj>,称Vi是Vj的直接前驱,Vj是Vi的直接后继,这种前驱与后继的关系具有传递性。

如果一个图的任何一个节点都具有反自反性,也就是说任何一个节点都不是自己的前驱或后继,那么这个有向图是拓扑有序的。

拓扑序列:

通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。离散数学中关于偏序和全序的定义:
  若集合X上的关系是R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
  设R是集合X上的偏序(Partial Order),如果对每个x,y属于X必有xRy 或 yRx,则称R是集合X上的全序关系。
  注意:
  ①若将图中顶点按拓扑次序排成一行,则图中所有的有向边均是从左指向右的。
  ②若图中存在有向环,则不可能使顶点满足拓扑次序。

  ③一个DAG的拓扑序列通常表示某种方案切实可行。

拓扑排序的一个应用是可以有向图中是否存在有向环。如果一个有向图存在环,那么必然存在结点不具有反自反性,因而相应的拓扑有序序列是不存在的。。

拓扑排序方法如下:

  (1)从有向图中选择一个没有前驱(即入度为0)的顶点并且输出它.
  (2)从网中删去该顶点,并且删去从该顶点发出的全部有向边.
  (3)重复上述两步,直到剩余的网中不再存在没有前趋的顶点为止.

 hdu 1285 确定比赛名次 链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285

 解法:拓扑排序,找到一个人,没人能赢他,或者能赢他的人都已经输出,即他的入度为0,则输出此人。注意重边。。。

代码:

View Code 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int n,m,sum;
 6 int map[501][501],degree[501],a[501],b[501];
 7 void topo(int x)
 8 {
 9     int i;
10     a[x]=1;
11     b[++sum]=x;
12     for(i=1;i<=n;i++)
13         if(!a[i]&&map[x][i])
14             degree[i]--;
15 }
16 int main()
17 {
18     int i,x,y;
19     while(~scanf("%d%d",&n,&m))
20     {
21         memset(map,0,sizeof(map));
22         memset(degree,0,sizeof(degree));
23         memset(a,0,sizeof(a));
24         for(i=0;i<m;i++)
25         {
26             scanf("%d%d",&x,&y);
27             if(map[x][y]==0)
28             {
29                 map[x][y]=1;
30                 degree[y]++;
31             }
32         }
33         sum=0;
34         while(sum<n)
35         {
36             for(i=1;i<=n;i++)
37             {
38                 if(degree[i]==0&&a[i]==0)
39                 {
40                     topo(i);
41                     break;
42                 }
43             }
44         }
45         for(i=1;i<sum;i++)
46             printf("%d ",b[i]);
47         printf("%d\n",b[i]);
48     }
49     return 0;
50


hdu 2094 产生冠军 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2094 

解法:这个跟上个题基本上一样,确定能不能产生冠军,能产生冠军即入度为0的点只有一个。也可以先用并查集来判断能不能形成连通图。

代码:

View Code 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 using namespace std;
 6 int nu,m,sum;
 7 int map[1001][1001];
 8 int degree[1001];
 9 char s[1001][51];
10 int a[1001];
11 int find(char *ss)
12 {
13     int i;
14     for(i=0;i<nu;i++)
15     {
16         if(strcmp(ss,s[i])==0)
17             return i;
18     }
19     strcpy(s[i],ss);
20     return nu++;
21 }
22 int topo()
23 {
24     int i,l=0;
25     for(i=0;i<nu;i++)
26         if(!degree[i])
27             l++;
28     return l;
29 }
30 int main()
31 {
32     char s1[101],s2[101];
33     int i,x,y;
34     while(~scanf("%d",&m))
35     {
36         if(m==0)
37             break;
38         nu=0;
39         memset(map,0,sizeof(map));
40         memset(degree,0,sizeof(degree));
41         memset(a,0,sizeof(a));
42         for(i=0;i<m;i++)
43         {
44             scanf("%s %s",s1,s2);
45             x=find(s1);
46             y=find(s2);
47             if(map[x][y]==0)
48             {
49                 map[x][y]=1;
50                 degree[y]++;
51             }
52         }
53         if(topo()==1)
54         puts("Yes");
55         else
56         puts("No");
57     }
58     return 0;
59

POJ 1094 Sorting It All Out  链接: http://poj.org/problem?id=1094

代码:

View Code 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int n,m,j,i,q,flag1;
 6 int map[100][100],degree[100],t[100],b[100];;
 7 int topo()
 8 {
 9     int i,j,f=1,p,temp,k=0;
10     for(i=0;i<n;i++)
11         t[i]=degree[i];
12     for(i=0;i<n;i++)
13     {
14         p=0;
15         for(j=0;j<n;j++)
16             if(t[j]==0)
17             {
18                 p++;
19                 temp=j;
20             }
21         if(p==0)
22             return 0;
23         if(p>1)
24             f=-1;
25         b[k++]=temp;
26         t[temp]=-1;
27         for(j=0;j<n;j++)
28             if(map[temp][j]!=0)
29                 t[j]--;
30     }
31     return f;
32 }
33 int main()
34 {
35     while(~scanf("%d %d",&n,&m))
36     {
37         flag1=0;
38         char c1,c2;
39         if(n==0&&m==0)
40             break;
41         memset(map,0,sizeof(map));
42         memset(degree,0,sizeof(degree));
43         for(i=0;i<m;i++)
44         {
45             scanf("%*c%c<%c",&c1,&c2);
46             map[c1-'A'][c2-'A']=1;
47             degree[c2-'A']++;
48             if(flag1==0)
49                 q=topo();
50             if(q==1&&flag1==0)
51             {
52                 printf("Sorted sequence determined after %d relations: ",i+1);
53                 for(j=0;j<n;j++)
54                     printf("%c",b[j]+'A');
55                 printf(".\n");
56                 flag1=1;
57             }
58             if(q==0&&flag1==0)
59             {
60                 printf("Inconsistency found after %d relations.\n",i+1);
61                 flag1=1;
62             }
63         }
64         if(flag1==0)
65             printf("Sorted sequence cannot be determined.\n");
66     }
67     return 0;
68


POJ 2367 Genealogical tree  链接: http://poj.org/problem?id=2367

代码:

View Code 
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int N=102;
 6 int degree[N],map[N][N],a[N],b[N];
 7 int n,s;
 8 void topo(int x)
 9 {
10     int i;
11     a[x]=1;
12     b[++s]=x;
13     for(i=1;i<=n;i++)
14     {
15         if(!a[i]&&map[x][i])
16         {
17             degree[i]--;
18         }
19     }
20 }
21 int main()
22 {
23     int x,i;
24     scanf("%d",&n);    
25     memset(a,0,sizeof(0));
26     memset(degree,0,sizeof(degree));
27     memset(map,0,sizeof(map));
28     for(i=1;i<=n;i++)
29     {
30         while(1)
31         {
32             scanf("%d",&x);
33             if(x==0)
34                 break;
35             map[i][x]=1;
36             degree[x]++;
37         }
38     }
39     s=0;
40     while(s<n)
41     {
42         for(i=1;i<=n;i++)
43         {
44             if(degree[i]==0&&a[i]!=1)
45             {
46                 topo(i);
47             }
48         }
49     }
50     for(i=1;i<n;i++)
51         printf("%d ",b[i]);
52     printf("%d\n",b[i]);
53     return 0;
54

poj 3687 Labeling Balls 链接:http://poj.org/problem?id=3687

题意:n个重量分别为1-n的小球,给定一些小球间的重量关系。 在符合重量关系的前提下,先输出编号小的球。

分析:拓扑排序,倒着来,注意一下重边。。。

代码:

View Code 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int N=210;
 6 int map[N][N],degree[N],a[N],b[N];
 7 int n, m;
 8 void topo()
 9 {
10     int i,j;
11     memset(a,0,sizeof(a));
12     for(i=n;i>0;i--)
13     {
14         int q=-1;
15         for(j=n-1;j>=0;j--)
16             if(!a[j]&&degree[j]==0)
17             {
18                 q=j;
19                 break;
20             }
21         if(q==-1)
22         {
23             puts("-1");
24             return;
25         }
26         a[q]=1;
27         b[q]=i;
28         for(j=0;j<n;j++)
29             if(map[q][j])
30                 degree[j]--;
31     }
32     for(i=0;i<n-1;i++)
33         printf("%d ",b[i]);
34     printf("%d\n",b[i]);
35 }
36 int main()
37 {
38     int t;
39     scanf("%d",&t);
40     while(t--)
41     {
42         int i;
43         scanf("%d%d",&n,&m);
44         memset(map,0,sizeof(map));
45         memset(degree,0,sizeof(degree));
46         for(i=0;i<m;i++)
47         {
48             int a,b;
49             scanf("%d%d",&a,&b);
50             a--;
51             b--;
52             if(!map[b][a])
53                 degree[a]++;
54             map[b][a]=true;
55         }
56         topo();
57     }
58     return 0;
59
原文地址:https://www.cnblogs.com/pony1993/p/2606678.html