给定一个有向图G,对于任意一条有向边<Vi,Vj>,称Vi是Vj的直接前驱,Vj是Vi的直接后继,这种前驱与后继的关系具有传递性。
如果一个图的任何一个节点都具有反自反性,也就是说任何一个节点都不是自己的前驱或后继,那么这个有向图是拓扑有序的。
拓扑序列:
③一个DAG的拓扑序列通常表示某种方案切实可行。
拓扑排序的一个应用是可以有向图中是否存在有向环。如果一个有向图存在环,那么必然存在结点不具有反自反性,因而相应的拓扑有序序列是不存在的。。
拓扑排序方法如下:
hdu 1285 确定比赛名次 链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285
解法:拓扑排序,找到一个人,没人能赢他,或者能赢他的人都已经输出,即他的入度为0,则输出此人。注意重边。。。
代码:
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的点只有一个。也可以先用并查集来判断能不能形成连通图。
代码:
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
代码:
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
代码:
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的小球,给定一些小球间的重量关系。 在符合重量关系的前提下,先输出编号小的球。
分析:拓扑排序,倒着来,注意一下重边。。。
代码:
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]&°ree[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