题意:给定一个N点M边的有向图,叫你加最多K条边,使得最小拓扑序最大.
思路:不是那么简单的题. 参照了别人的代码,最后想通了.
贪心原则, 用两个单调队列维护, 第一个序列S1单增, 表示当前入度为0的点 ; 第二个序列S2单减,表示需要加边的点.
对于第一个集合, 显然小的点更需要加边,所以在K还有剩余的时候,把S1的最小值加入S2, 如果K没有剩余. 那么从小到大输出.
而S1和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; }