题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=4110
题目大意:
拓扑排序。
但是本题的要求不是拓扑序列字典序最小,
而是1~N号球所对应的排序后的位置构成的序列字典序最小,
也就是,在满足编号1尽量靠前的条件下,编号2要尽量靠前,在满足前两个条件下,编号3尽量靠前,依次类推。
算法:
反向思维,倒序拓扑。
每次让序号大的球尽量往后排。
因为从后往前排的时候,
决定的位置就是越来越重要的,
然后不断有新的顶点入队,
如果这里面有更小的顶点,就可以把它放到前面去。
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int head[210],d[210],ans[210],top,E; struct { int u,v,w,nxt; } edge[41000]; void addedge(int u,int v) { edge[E].u=u; edge[E].v=v; edge[E].nxt=head[u]; head[u]=E++; } int main() { int n,m,cas; scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); memset(d,0,sizeof(d)); E=0; while(m--) { int u,v; scanf("%d%d",&u,&v); addedge(v,u); d[u]++; } priority_queue<int>qq; for(int i=1; i<=n; i++) { if(!d[i]) qq.push(i); } top=n; while(!qq.empty()) { int u=qq.top(); qq.pop(); ans[u]=top--; for(int i=head[u]; i!=-1; i=edge[i].nxt) { d[edge[i].v]--; if(!d[edge[i].v]) qq.push(edge[i].v); } } if(top) { puts("-1\n"); continue; } for(int i=1; i<=n; i++) { if(i>1)putchar(' '); printf("%d",ans[i]); } puts("\n"); } return 0; }