1. 程式人生 > >Gym - 100801G: Graph (貪心+set+拓撲)(好題)

Gym - 100801G: Graph (貪心+set+拓撲)(好題)

|| tor pop spa lse 好題 兩個 clu strong

題意:給定一個N點M邊的有向圖,叫你加最多K條邊,使得最小拓撲序最大.

思路:不是那麽簡單的題. 參照了別人的代碼,最後想通了.

貪心原則: 用兩個單調隊列維護, 第一個序列S1單增, 表示當前入度為0的點 ; 第二個序列S2單減,表示需要加邊的點.

如果S1的最大值大於S2的最大值,則對其加邊.

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
priority_queue<int>p;
priority_queue<int,vector<int>,greater<int
> >q; vector<int>G[maxn]; int cnt,ind[maxn]; int num,used,ans[maxn],a[maxn],b[maxn]; void del(int v){ ans[++num]=v; for(int i=0;i<G[v].size();i++) if(!--ind[G[v][i]]) q.push(G[v][i]); if(q.empty()){ if(!p.empty()){ int c=p.top(); p.pop(); G[ans[num]].push_back(c); a[
++used]=ans[num]; b[used]=c; del(c); } } } int main() { int N,M,K,u,v,i,j; scanf("%d%d%d",&N,&M,&K); for(i=1;i<=M;i++){ scanf("%d%d",&u,&v); G[u].push_back(v); ind[v]++; } for(i=1;i<=N;i++) if
(!ind[i]) q.push(i); while(!q.empty()){ if(K&&(q.size()>1||(!p.empty()&&q.top()<p.top()))){ K--; int c=q.top(); p.push(c); q.pop(); if(q.empty()){ int c=p.top(); p.pop(); G[ans[num]].push_back(c); a[++used]=ans[num]; b[used]=c; del(c); } } else{ int c=q.top(); q.pop(); del(c); } } return 0; }

Gym - 100801G: Graph (貪心+set+拓撲)(好題)