1. 程式人生 > 其它 >P3243 [HNOI2015]菜餚製作(拓撲+優先佇列+貪心)

P3243 [HNOI2015]菜餚製作(拓撲+優先佇列+貪心)

題目傳送門

思路

一開始會很顯然的想到要用拓撲排序,想著不就是要找字典序最小的拓撲序列嘛,那也太水了,於是,發現有問題,正著的時候 我得知道他的葉子節點的最小值,然後跑當前根節點到葉子結點最小值的絕對路徑,但是這樣不好搞。
於是乎,想到建立反圖,從最小值開始跑,那麼從最小值跑到葉子節點的路徑就是答案,然後其實對於每一層還是要跑拓撲,因為是反一反 所以就丟一個優先佇列,跑值最大的點就行,然後最後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;
}