洛谷3243 [HNOI2015]菜肴制作
阿新 • • 發佈:2018-08-24
倒序輸出 problem pac www names mem show sizeof 反向
Coding
題目戳這裏
Solution
錯誤的想法:正向建圖,然後從入度為0的點選出最小u的開始輸出,然後找出u連接的點v,並把v的度數減一,再次把入度為0的點加入小根堆,這樣顯然有錯,因為只能局部保證最小,後面的情況便無法確定。
Hack數據: n=3,m=1 限制:<3,1>
按照之前的思路,3和2的入度為0,那麽取出更小的2,所以答案為2,3,1,但是答案顯然為3,2,1。
那麽怎麽辦? 正向建圖不行,那麽我們就反向建圖,再倒序輸出,這樣保證越大的越晚輸出,就OK了!
具體做法:本蒟蒻因為topsort用得不熟,所以只好用大根堆模擬 ,首先把入讀為0的點加入大根堆,每次取出u(因為是大根堆,所以保證u是堆中最大的),再找出u連接的點v,並把v的度數減一,再次把入度為0的點加入大根堆,最後反向輸出。
PS:雖然思路比較難想,但代碼實現還是很容易的!
Coding
#include<bits/stdc++.h> using namespace std; const int N = 5e5; struct road { int to,next; }e[N*5]; priority_queue <int> q; int cntt,ans[N],head[N],n,m,in[N],out[N]; void add(int x,int y) { cntt++; e[cntt].to=y; e[cntt].next=head[x]; head[x]=cntt; } int main() { int T; cin>>T; while(T--) { cntt=0; memset(head,0,sizeof(head)); memset(in,0,sizeof(in)); int cnt=0; cin>>n>>m; for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); add(y,x); in[x]++; } for(int i=1;i<=n;i++) if(in[i]==0) q.push(i); int flag=0; while(1) { cnt++; int x=q.top(); ans[cnt]=x; q.pop(); for(int i=head[x];i;i=e[i].next) { int v=e[i].to; in[v]--; if(in[v]==0) q.push(v); } if(cnt==n) break ; if(q.empty()) {cout<<"Impossible!"<<endl; flag=1;break;} } if(!flag) { for(int i=n;i>=1;i--) printf("%d ",ans[i]); cout<<endl; } } return 0; }
洛谷3243 [HNOI2015]菜肴制作