洛谷P3243/LOJ2114/BZOJ4010[HNOI2015]菜肴制作(拓扑排序)
首先直接跑拓扑排序,编号小的排前面是错误的,这组数据就可以hack掉:
4 2
3 1
2 4
答案:3 1 2 4
错误输出:2 3 1 4
其实,反过来,编号大的排后面就是对的了。
为什么呢?反证法:考虑输出序列与答案序列不同的编号最小的数,记它的位置为$p$,答案$p'$,由题意可知$p>p'$,且因为我们找的是编号最小的数,输出内位置为$p'$的数编号更大,这与我们要求的“编号大的排后面”矛盾,所以输出就是答案。
#include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=100050; char rB[1<<21],*S,*T; inline char gc(){return S==T&&(T=(S=rB)+fread(rB,1,1<<21,stdin),S==T)?EOF:*S++;} inline int rd(){ char c=gc(); while(c<48||c>57)c=gc(); int x=c&15; for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } int G[N],to[N],nxt[N],sz,d[N],s[N]; priority_queue<int> Q; inline void add(int u,int v){ to[++sz]=v;nxt[sz]=G[u];G[u]=sz; } int main(){ int T=rd(),n,m,i,u,v,tot; while(T--){ tot=n=rd();m=rd(); memset(G,0,sizeof(G));sz=0; memset(d,0,sizeof(d)); while(m--){ u=rd();v=rd(); add(v,u); ++d[u]; } for(i=1;i<=n;++i)if(!d[i])Q.push(i); while(!Q.empty()){ u=Q.top();Q.pop(); s[tot--]=u; for(i=G[u];i;i=nxt[i])if(!--d[v=to[i]])Q.push(v); } if(tot)puts("Impossible!"); else{ for(i=1;i<=n;++i)printf("%d ",s[i]); putchar('\n'); } } return 0; }