P3243 [HNOI2015]菜餚製作(拓撲+優先佇列+貪心)
阿新 • • 發佈:2022-04-04
思路
一開始會很顯然的想到要用拓撲排序,想著不就是要找字典序最小的拓撲序列嘛,那也太水了,於是,發現有問題,正著的時候 我得知道他的葉子節點的最小值,然後跑當前根節點到葉子結點最小值的絕對路徑,但是這樣不好搞。
於是乎,想到建立反圖,從最小值開始跑,那麼從最小值跑到葉子節點的路徑就是答案,然後其實對於每一層還是要跑拓撲,因為是反一反 所以就丟一個優先佇列,跑值最大的點就行,然後最後reverse一下。
code
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; //#pragma GCC optimize(3) #define pb push_back #define is insert #define PII pair<int,int> #define PLL pair<ll,ll> #define show(x) cerr<<#x<<" : "<<x<<endl; //mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count()); //ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);} const int INF=0x3f3f3f3f;//2147483647; const int N=1e5+50,M=1e4+50; const ll mod=1e9+7; int n,m; vector<int>to[N]; vector<int>ans; int in[N]; priority_queue<int>q; void solve() { cin>>n>>m; for(int i=1;i<=m;i++){ int u,v;cin>>u>>v; to[v].pb(u); in[u]++; } int cnt=0; for(int i=1;i<=n;i++){ if(in[i]==0){ q.push(i); } } while(!q.empty()){ int u=q.top();cnt++;q.pop(); ans.pb(u); for(auto i:to[u]){ in[i]--; if(!in[i]){ q.push(i); } } } if(cnt!=n){ cout<<"Impossible!"<<"\n"; } else { reverse(ans.begin(),ans.end()); for(auto i:ans){ cout<<i<<" "; }cout<<"\n"; } ans.clear(); for(int i=1;i<=n;i++){ to[i].clear(); in[i]=0; } } signed main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int __=1;cin>>__; while(__--){ solve(); } return 0; }