开始刷BC了。第一题就被卡住了QAQ。题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857
题意大抽象后概是这样的:给定一个有向图,将其按线性优先级输出。题目大致一扫,可以明白是个赤果果的拓扑排序。以前学过一点拓扑排序,后来给忘掉
了。拓扑排序就是解决对有向图的点进行线性排序的相关问题。假设给定一标记优先级的有向图,那么每个有向边通向的点的入度都要+1,这样的标记后,入度为
0的点就可以看成是优先级最高的点(因为没有点在它前面去连接它)。把此点取出,与这个点相连的其他点的边也就全部都要消掉了,同时将它们的入度减去1;
这样会产生新的入度为0的点,那么这个点就是剩下的点中的优先级最高的点,重复上述的更新过程即可。此题有坑,可能会有多个拓扑环;还有此题要求输出的点
如果没有拓扑关系则按照小编号在前的方式排列。看到这个条件第一反应是在取优先级高的点的过程中用优先队列去写,先出队列的就是编号较小的,这么想似乎没
错。但是后来debug了下,假如有一有向图关系是这样的:6->3->1;5->4->2;这样的话按照最小堆来进行拓扑排序会出这样的结果:5 4 2 6 3 1;但是实际上
我们可以把6 3 1 这个拓扑环放在前面,生成6 3 1 5 4 2这样的线性序列。究其原因,我们优先队列先弹出的是编号较小的符合条件的点,但实际上这个点只能算
是该拓扑环排序后的头结点,我们想要保证让小号的全部尽可能地放在前面,我们需要保证拓扑环的尾部的小号也在前面。这样来想一下可以发现先出编号小的是
不完善的。于是我们可以考虑逆向思维,先弹出序号大的,那么这样先出队列的就是编号最大的;但是我们有需要编号最大的在最后输出,换句话说就是编号最大的
是作为优先级最低的;那么我们把有向图也给逆向储存,这样按优先级条件弹出的顺序才会一致(优先弹出优先级最低的)。大致思路明白后代码实现就很简单了。
#include <bits/stdc++.h> using namespace std; int in[50000], ans[50000], cnt, n; vector<int>G[50000]; struct ad { int id; bool operator < (const ad t)const { return t.id > id; } }; void Topsort() { cnt = 0; priority_queue<ad>Q; ad s; for(int i=1; i<=n; i++) { if(in[i] == 0) { s.id = i; Q.push(s); } } while(!Q.empty()) { s = Q.top(); Q.pop(); ans[cnt++] = s.id; int x = s.id; for(int i=0; i<G[x].size(); i++) { int y = G[x][i]; in[y]--; if(in[y] == 0) { s.id = y; Q.push(s); } } } for(int i=cnt-1; i>=0; i--) printf("%d%c", ans[i], i==0?' ':' '); } int main() { int T, m; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); memset(in, 0, sizeof(in)); for(int i=1; i<=n; i++) G[i].clear(); for(int i=1; i<=m; i++) { int a, b; scanf("%d %d", &a, &b); in[a]++; G[b].push_back(a); } Topsort(); } return 0; }