BZOJ4010 HNOI2015 菜肴制作 貪心、拓撲排序
阿新 • • 發佈:2019-02-06
empty == 字典序 ons n) 需要 efi mat 拓撲排序
的點中編號最大的,這樣就可以得到一個正確的排列了。
傳送門
顯然是拓撲排序
但是並沒有那麽簡單
看起來需要字典序最小,那就拿個堆代替隊列,按照點編號大小拓撲排序,然後你就WA了;還不服輸,按照能夠到達的最小編號的點為第一關鍵字,點的編號為第二關鍵字拓撲排序,結果還是WA了,因為這種貪心只能保證最小的在最前面,不能保證最小的在最前面的前提下次小在最前面……
正著不對,不妨倒著考慮
既然編號小的要盡可能在前面訪問,那麽編號最大的一定要盡可能在最後面。也就是說:最後一個訪問的一定是當前出度為\(0\)的點中出度最大的點,將它去掉之後出度為\(0\)的點中編號最大的點會在第\(N-1\)個訪問……
那麽正確的貪心策略就是:反圖上拓撲排序,貪心地選擇當前入度為\(0\)
#include<bits/stdc++.h> //This code is written by Itst using namespace std; inline int read(){ int a = 0; char c = getchar(); bool f = 0; while(!isdigit(c)){ if(c == ‘-‘) f = 1; c = getchar(); } while(isdigit(c)){ a = (a << 3) + (a << 1) + (c ^ ‘0‘); c = getchar(); } return f ? -a : a; } #define PII pair < int , int > const int MAXN = 1e5 + 7; struct Edge{ int end , upEd; }Ed[MAXN]; int head[MAXN] , in[MAXN] , ans[MAXN]; int N , M , cntEd; bool vis[MAXN] , ins[MAXN]; inline void addEd(int a , int b){ Ed[++cntEd].end = b; Ed[cntEd].upEd = head[a]; head[a] = cntEd; ++in[b]; } priority_queue < int > q; void tSort(){ for(int i = 1 ; i <= N ; ++i) if(!in[i]) q.push(i); int cnt = 0; while(!q.empty()){ int t = q.top(); q.pop(); ans[N - cnt++] = t; for(int i = head[t] ; i ; i = Ed[i].upEd) if(!--in[Ed[i].end]) q.push(Ed[i].end); } if(cnt < N) puts("Impossible!"); else{ for(int i = 1 ; i <= N ; ++i) printf("%d " , ans[i]); putchar(‘\n‘); } } int main(){ #ifndef ONLINE_JUDGE freopen("in" , "r" , stdin); freopen("out" , "w" , stdout); #endif for(int D = read() ; D ; --D){ N = read(); M = read(); memset(head , 0 , sizeof(head)); memset(vis , 0 , sizeof(vis)); memset(in , 0 , sizeof(in)); cntEd = 0; for(int i = 1 ; i <= M ; ++i){ int a = read() , b = read(); addEd(b , a); } tSort(); } return 0; }
BZOJ4010 HNOI2015 菜肴制作 貪心、拓撲排序