题意:给n个点m条边的DAG,最多可以添加k条边,问添加后的图的最小拓扑序的最大值是多少。
分析:开两个set,一个维护当前入度为0的所有点,一个用来维护需要被加边的点,然后对于第一个set中值最小的点,如果set中还有其他点且k还没用完,那么我们便直接把它扔进第二个set中待处理,否则直接将其打印出;如果第一个set中只有这一个点,我们便考虑能不能从第二个set中找一个最大的点来代替它,然后不断迭代直到两个set都为空。
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#include <unordered_map>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MAXN 100005
#define MOD 1000000007
using namespace std;
set<int> f,f2;
int n,m,k,rd[MAXN],ans[MAXN],Ans[MAXN][2];
vector <int> G[MAXN];
int main()
{
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i <= m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);
rd[y]++;
}
for(int i = 1;i <= n;i++)
if(!rd[i]) f.insert(i);
int now = 0,use = 0,use2 = 0;
while(f.size())
{
set<int> :: iterator it = f.begin();
set<int> :: iterator itmax = f2.end();
int u = *it;
f.erase(it);
if(f.size() && use != k)
{
use++;
f2.insert(u);
}
else
{
if(!f2.empty()) itmax--;
if(f2.empty() || *itmax < u || use == k)
{
ans[++now] = u;
for(int v : G[u])
{
rd[v]--;
if(!rd[v]) f.insert(v);
}
}
else
{
use++;
f2.insert(u);
for(int v : G[*itmax])
{
rd[v]--;
if(!rd[v]) f.insert(v);
}
Ans[++use2][0] = ans[now];
Ans[use2][1] = *itmax;
ans[++now] = *itmax;
f2.erase(itmax);
}
}
while(f.empty() && !f2.empty())
{
set<int> :: iterator itmax = f2.end();
itmax--;
Ans[++use2][0] = ans[now];
Ans[use2][1] = *itmax;
ans[++now] = *itmax;
for(int v : G[*itmax])
{
rd[v]--;
if(!rd[v]) f.insert(v);
}
f2.erase(itmax);
}
}
for(int i = 1;i < n;i++) cout<<ans[i]<<" ";
cout<<ans[n]<<endl;
cout<<use2<<endl;
for(int i = 1;i <= use2;i++) cout<<Ans[i][0]<<" "<<Ans[i][1]<<endl;
}