题解:P7054 [NWRRC2015] Graph
观察题目,我们要让字典序最小,就是要让第一位最小,然后第二位,以此类推,则可以想到贪心。
连 $k$ 条边,就是要在拓扑排序中有 $k$ 步可以选择,且每一步找一个小一点的点来连。那么这个点怎么连呢?
这里参考了 @dengduck 大佬的思路,直接把所有这样的点用一个大根堆存起来,在拓扑的过程中取出来用。
同时,要字典序最小,需要把拓扑排序的队列换成小根堆,并且记录路径。
注意:如果你的代码没过样例不着急
不要忘了有
special judge
,对于第一组样例,这个输出是可以的(被耽误了很久):
5 1 4 2 3
2
5 1
2 3
Code
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
using LL=long long;
LL n,m,in[500005],k,tmp[500005],cnt;
vector<LL> v[500005],order;
priority_queue<LL,vector<LL>,greater<LL> > q;
priority_queue<LL,vector<LL>,less<LL> > p;
vector<pair<LL,LL> > res;
void topsort(){
for(int i=1;i<=n;i++) if(!in[i]) q.push(i);
while((q.size()+p.size())){
cnt++;tmp[cnt]=tmp[cnt-1];
while(min(k,LL(q.size()))){
if(q.top()>(!p.empty() ? p.top() : 0)&&q.size()==1) break;
p.push(q.top()),q.pop(),k--;
}
if(!q.empty()){
tmp[cnt]=q.top(),q.pop();
} else{
tmp[cnt]=p.top(),p.pop();
if(tmp[cnt-1]) res.push_back({tmp[cnt-1],tmp[cnt]});
}
for(auto i : v[tmp[cnt]]){
in[i]--;
if(!in[i]) q.push(i);
}
order.push_back(tmp[cnt]);
}
return ;
}
int main(){
cin>>n>>m>>k;
for(int i=1,x,y;i<=m;i++){
cin>>x>>y;
v[x].push_back(y);
in[y]++;
}
topsort();
for(auto i : order){
cout<<i<<' ';
}
cout<<endl;
cout<<res.size()<<endl;
for(auto i : res){
cout<<i.first<<' '<<i.second<<endl;
}
return 0;
}