BZOJ4010 [HNOI2015]菜肴制作[拓扑排序+贪心]

其实有些题真的是,即使翻看了题解,也可以解释一二原因,也并不能对这种做法有深深的认同感。。


因为题意说的是让序号小的优先在拓扑序中向左靠,也就是说,比如1号会被前面很多大序号的节点“堵住”,但是仍要优先让他先出来,所以这时候按字典序最小来做拓扑是不对的。。`````

反过来考虑:

引理:对于一张DAG,其任意一个拓扑序的倒序和这张反向的DAG的拓扑序一一对应。

证明:不会证明。对于出现在原拓扑序末尾的一段,一定是没有出度的节点,那么反图中,他们没有入度,所以可以出现在拓扑序开头,而末尾再向前一段的点(假设为$x$)是有出度的,且指向这些没有出度的点,这在反图中就对应了没有入度的点删掉后,继续选择$x$为零入度点。以此类推。所以正拓扑序反序和反图拓扑序对应,同理,后者也与前者对应。

反正这个是超有道理的啦(っ ̄▽ ̄)っ。

于是,建一张反的DAG,并且采用字典序从大到小的方法拓扑排序。为什么这样做?因为,首先反向的拓扑序是和正向拓扑序等价的,这是前提。然后,在所有入度为0的点里,我们要选择最大的,因为,如果我们先选择了小序号的放在后面,那么明显他应该再往左靠,也就是说,小数字比大数字向左靠的优先级高。这样,一个拓扑序中,大数尽量放后面,“让”给小数,让小数尽量靠左。这样的贪心就是对的。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<queue>
 7 #define mst(x) memset(x,0,sizeof x)
 8 #define dbg(x) cerr << #x << " = " << x <<endl
 9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
10 using namespace std;
11 typedef long long ll;
12 typedef double db;
13 typedef pair<int,int> pii;
14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
19 template<typename T>inline T read(T&x){
20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
22 }
23 const int N=1e5+7;
24 int T,n,m,flag;
25 struct thxorz{int nxt,to;}G[N];
26 int Head[N],tot;
27 inline void Addedge(int x,int y){G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot;}
28 #define y G[j].to
29 //int dfn[N],low[N],cnt,stk[N],instk[N],Top;
30 //void tarjan(int x){
31 //    dfn[x]=low[x]=++cnt,stk[++Top]=x,instk[x]=1;
32 //    for(register int j=Head[x];j;j=G[j].nxt){
33 //        if(!dfn[y])tarjan(y),MIN(low[x],low[y]);
34 //        else if(instk[y])MIN(low[x],dfn[y]);
35 //    }
36 //    if(dfn[x]==low[x]){
37 //        int tmp,cnt=0;
38 //        do instk[tmp=stk[Top--]]=0,++cnt;while(tmp^x);
39 //        if(cnt>1)flag=1;
40 //    }
41 //}
42 int ans[N],r,deg[N];
43 priority_queue<int> pq;
44 inline void toposort(){
45     for(register int i=1;i<=n;++i)if(!deg[i])pq.push(i);
46     while(!pq.empty()){
47         ans[++r]=pq.top();pq.pop();
48         for(register int j=Head[ans[r]];j;j=G[j].nxt)
49             if(!(--deg[y]))pq.push(y);
50     }
51 }
52 #undef y
53 
54 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
55     read(T);while(T--){
56         read(n),read(m);
57         flag=tot=r=0;mst(Head),mst(deg);//mst(dfn),mst(low);
58         for(register int i=1,x,y;i<=m;++i)read(x),read(y),Addedge(y,x),++deg[x];
59 //        for(register int i=1;i<=n;++i)if(!dfn[i])Top=0,tarjan(i);
60 //        if(flag){puts("Impossible!");continue;}
61         toposort();
62         if(r<n){puts("Impossible!");continue;}
63         for(register int i=n;i;--i)printf("%d ",ans[i]);puts("");
64     }
65     return 0;
66 }
     View     Code     

总结:正向不便不妨建反图考虑。然而还是个套路、

posted @ 2019-10-22 09:24  Ametsuji_akiya  阅读(157)  评论(0编辑  收藏  举报