洛谷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;
}
View Code

 

posted @ 2019-07-28 15:28  wangyuchen  阅读(106)  评论(0编辑  收藏  举报