gym 100801G.Graph(拓撲排序,貪心構造)
阿新 • • 發佈:2018-12-24
題意:
給出 個點 條邊的 ,要求最多加 條有向邊(不能形成環),使得可能的字典序最小的拓撲序列最大。輸出最終最小的拓撲序列,以及加邊數,加的邊()
題解:
用兩個優先佇列 ,一個是小元素在前,另一個是大元素在前,前一個維護當前入度為0的所有點,一個用來維護需要被加邊的點,然後對於 中值最小的點,如果其中還有其他點且k還沒用完,那麼我們便直接把它扔進 中待處理,這樣就是讓小的元素晚點拓撲出來;如果第 中只有這一個點,我們便考慮能不能從 中找一個最大的點來代替它拓撲出去,然後不斷迭代直到兩個佇列都為空。
#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;
}