gym 100801G.Graph(拓扑排序,贪心构造)
题意:
给出 \(n\) 个点 \(m\) 条边的 \(DAG\),要求最多加 \(k\) 条有向边(不能形成环),使得可能的字典序最小的拓扑序列最大。输出最终最小的拓扑序列,以及加边数,加的边(\(1 \leq n \leq 10^5,0 \leq m \leq 10^5\))
题解:
用两个优先队列 \(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;
}