拓扑排序小结
例题一、 HDU-1285
有N个比赛队(1<=N<=500),编号依次为1,2,3,……,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。
Input输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。
Output给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
Sample Input
4 3
1 2
2 3
4 3
Sample Output
1 2 4 3
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<queue>
5 using namespace std;
6 const int maxn=100000;
7 struct node{
8 int to;
9 int next;
10 }e[maxn];
11 int head[maxn],in[maxn],vis[maxn];
12 int cnt;
13 int m,n;
14 void init()
15 {
16 memset(head,-1,sizeof(head));
17 memset(in,0,sizeof(in));
18 cnt=0;
19 }
20 int ans;
21 void add(int a,int b)
22 {
23 e[cnt].to=b;
24 e[cnt].next=head[a];
25 head[a]=cnt++;
26 }
27 void topu()
28 {
29 ans=0;
30 priority_queue<int,vector<int>,greater<int> >q;
31 for(int i=1;i<=n;i++)
32 {
33 if(in[i]==0)
34 {
35 q.push(i);
36 }
37 }
38 while(!q.empty())
39 {
40 int v=q.top();
41 vis[ans++]=v;
42 q.pop();
43 for(int i=head[v];i!=-1;i=e[i].next)
44 {
45 int u=e[i].to;
46 if(--in[u]==0)
47 {
48 q.push(u);
49 }
50 }
51 }
52 for(int i=0;i<ans-1;i++)
53 {
54 printf("%d ",vis[i]);
55 }
56 printf("%d\n",vis[ans-1]);
57 }
58 int main()
59 {
60 while(~scanf("%d%d",&n,&m))
61 {
62 int a,b;
63 init();
64 for(int i=0;i<m;i++)
65 {
66 scanf("%d%d",&a,&b);
67 add(a,b);
68 in[b]++;
69 }
70 topu();
71 }
72 return 0;
73 }
例题二、HDU-2647 Reward
题目大意:一个厂主要给员工发工资,底薪888,员工中有人a要求工资高于b,厂主想满足所有人的要求并且使自己花费最少。输出最少花销。
注意:①员工最大10000,且并不是所有人之间都有关系,所以不能用邻接矩阵,应用邻接表。
②输入a,b是a要求工资比b多,所以应从b向a连边。
③判断-1的情况不是只判断是否存在入度为0的点,还要判断是否存在环的情况。
④注意max判断。
用邻接表存图的写法
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<queue>
5 #include<algorithm>
6 using namespace std;
7 const int maxn=10005;
8 int head[maxn],vis[maxn],in[maxn];
9 int money[maxn];
10 int m,n;
11 int tot=0,sum=0,ans=0;
12 struct node{
13 int to;
14 int next;
15 }e[2*maxn];
16 int cnt;
17 void init()
18 {
19 memset(head,-1,sizeof(head));
20 memset(vis,0,sizeof(vis));
21 memset(in,0,sizeof(in));
22 memset(money,0,sizeof(money));
23 cnt=0;
24 }
25 void add(int x,int y)
26 {
27 e[cnt].to=y;
28 e[cnt].next=head[x];
29 head[x]=cnt++;
30 }
31 void topu()
32 {
33 queue<int>q;
34 for(int i=1;i<=n;i++)
35 {
36 if(in[i]==0)
37 q.push(i);
38 }
39 while(!q.empty())
40 {
41 int v=q.front();
42 sum+=money[v];
43 q.pop();
44 ans++;
45 for(int i=head[v];i!=-1;i=e[i].next)
46 {
47 if(--in[e[i].to]==0)
48 {
49 q.push(e[i].to);
50 money[e[i].to]=money[v]+1;
51
52 }
53 }
54 }
55 }
56 int main()
57 {
58 int a,b;
59 while(~scanf("%d%d",&n,&m))
60 {
61 init();
62 tot=0,sum=0,ans=0;
63 for(int i=1;i<=n;i++)
64 {
65 money[i]=888;
66 }
67 while(m--)
68 {
69 scanf("%d%d",&a,&b);
70 add(b,a);
71 in[a]++;
72 }
73 topu();
74 if(ans!=n)
75 sum=-1;
76 printf("%d\n",sum);
77 }
78 return 0;
79 }
用vector存图的写法
1 #include<iostream>
2 #include<cstdio>
3 #include<queue>
4 #include<cstring>
5 #include<vector>
6 using namespace std;
7 const int maxn=21000;
8 int head[maxn],in[maxn],temp[maxn];
9 int n,m,cnt,sum;
10 vector<int>v[maxn];
11 int money[maxn];
12 int topu()
13 {
14 for(int i=1;i<=n;i++)
15 {
16 money[i]=888;
17 }
18 queue<int>q;
19 sum=0;
20 for(int i=1;i<=n;i++)
21 {
22 if(in[i]==0)
23 q.push(i);
24 }
25 int cnt=0;
26 while(!q.empty())
27 {
28 int tmp=q.front();
29 cnt++;
30 sum+=money[tmp];
31 q.pop();
32 for(int i=0;i<v[tmp].size();i++)
33 {
34 in[v[tmp][i]]--;
35 if(!in[v[tmp][i]])
36 {
37 q.push(v[tmp][i]);
38 money[v[tmp][i]]=money[tmp]+1;
39 }
40 }
41 }
42 if(cnt!=n)
43 return 1;
44 else
45 return 0;
46 }
47 int main()
48 {
49 int a,b;
50 int step,flag;
51 while(~scanf("%d%d",&n,&m))
52 {
53 memset(in,0,sizeof(in));
54 sum=0;
55 for(int i=0;i<maxn;i++)
56 {
57 v[i].clear();
58 }
59 memset(in,0,sizeof(in));
60 for(int i=1;i<=m;i++)
61 {
62 scanf("%d%d",&a,&b);
63 v[b].push_back(a);
64 in[a]++;
65 }
66 flag=topu();
67 if(flag==1)
68 {
69 printf("-1\n");
70 }
71 else
72 {
73 printf("%d\n",sum);
74 }
75 }
76
77 return 0;
78 }