1. 程式人生 > >gym 100801G.Graph(拓撲排序,貪心構造)

gym 100801G.Graph(拓撲排序,貪心構造)

題意:

給出 n 個點 m 條邊的 DAG,要求最多加 k 條有向邊(不能形成環),使得可能的字典序最小的拓撲序列最大。輸出最終最小的拓撲序列,以及加邊數,加的邊(1n105,0m105)

題解:

用兩個優先佇列 minQ,maxQ ,一個是小元素在前,另一個是大元素在前,前一個維護當前入度為0的所有點,一個用來維護需要被加邊的點,然後對於 minQ 中值最小的點,如果其中還有其他點且k還沒用完,那麼我們便直接把它扔進 maxQ 中待處理,這樣就是讓小的元素晚點拓撲出來;如果第 minQ 中只有這一個點,我們便考慮能不能從

maxQ 中找一個最大的點來代替它拓撲出去,然後不斷迭代直到兩個佇列都為空。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back #define fi first #define se second #define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<endl; typedef vector<int> VI; typedef long long ll; typedef pair<int,int> PII; const int inf=0x3fffffff; const ll mod=1000000007; const int maxn=1e5
+10; int head[maxn]; struct edge { int to,next; }e[maxn*2]; // int tol=0; void add(int u,int v) { e[++tol].to=v,e[tol].next=head[u],head[u]=tol; } priority_queue<int,vector<int>,greater<int> >minQ; priority_queue<int> maxQ; int d[maxn]; int ans[maxn]; vector<PII> res; void release(int u) { for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(--d[v]==0) minQ.push(v); } } int main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); int n,m,k; scanf("%d%d%d",&n,&m,&k); rep(i,1,m+1) { int u,v; scanf("%d%d",&u,&v); add(u,v); d[v]++; } rep(i,1,n+1) if(!d[i]) minQ.push(i); int len=0; while(len<n) { len++; while(k&&minQ.size()>1) { k--; int t=minQ.top(); minQ.pop(); maxQ.push(t); } if(minQ.size()==0) { int t=maxQ.top(); maxQ.pop(); ans[len]=t; release(t); res.pb(make_pair(ans[len-1],t)); } else if(minQ.size()==1&&k&&maxQ.size()&&minQ.top()<maxQ.top()) { k--; int t=maxQ.top(); maxQ.pop(); maxQ.push(minQ.top()); minQ.pop(); ans[len]=t; release(t); res.pb(make_pair(ans[len-1],t)); } else { int t=minQ.top(); minQ.pop(); ans[len]=t; release(t); } } rep(i,1,n+1) printf("%d ",ans[i]); puts(""); printf("%d\n",(int)res.size()); for(auto it:res) printf("%d %d\n",it.fi,it.se); return 0; }