题意:
给定n个点m条边的图,其中有的边是有向边,有的边是无向边。
现在要求你将每条无向边修改为有向边,问如何修改能使得图中不存在环。
判断是否有解,如果有解则输出一组解
数据范围:n<=2e5
解法:
对有向图拓扑排序并记录时间戳dfn。
对于每条无向边,令dfn小的点直线dfn大的点即可(比较显然,这样不会出现环)。
注意如果原图的有向图已经出现环那么无解
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
vector<pair<int,int> >temp;
vector<int>g[maxm];
int dfn[maxm];
int d[maxm];
int n,m;
signed main(){
int T;cin>>T;
while(T--){
cin>>n>>m;
//init
for(int i=1;i<=n;i++){
g[i].clear();
d[i]=0;
}
temp.clear();
//
for(int i=1;i<=m;i++){
int op,a,b;cin>>op>>a>>b;
if(!op){//无向
temp.push_back({a,b});
}else{//有向
g[a].push_back(b);
d[b]++;
}
}
//拓扑排序
int idx=0;//dfn
queue<int>q;
for(int i=1;i<=n;i++){
if(!d[i]){
q.push(i);
}
}
while(!q.empty()){
int x=q.front();q.pop();
dfn[x]=++idx;
for(int v:g[x]){
if(d[v]){
d[v]--;
if(!d[v]){
q.push(v);
}
}
}
}
//
if(idx!=n){//不是所有点都入队,那么说明出现环了
puts("NO");continue;
}else{
puts("Yes");
for(auto i:temp){
int a=i.first,b=i.second;
if(dfn[a]>dfn[b]){
swap(a,b);
}
cout<<a<<' '<<b<<endl;
}
for(int x=1;x<=n;x++){
for(int v:g[x]){
cout<<x<<' '<<v<<endl;
}
}
}
}
return 0;
}