题目链接
题目大意:
给n个点和m条边,在接下来的m行输入t,x,y三个数,如果t==0则说明边是无向边,否则表示有向边,方向有x->y,问你能不能在保证图中无环的情况下,将无向边变成有向边,如果能输出YES,同时输出所有边,否则输出NO
解题思路:
在输入边的时候分别记录下有向边和无向边,如果是有向边,则存入vector中留着做拓扑排序,无向边则只需要记录下来,因为无向边对拓扑排序没有贡献,然后对图做一次拓扑排序,将每个点标记拓扑序,最后输出无向边的时候只要由拓扑序小的指向拓扑序大的即可
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
template <typename T>inline void read(T& t){
char c=getchar();t=0;
int f=1;
while(!isdigit(c)){
if(c=='-')f=-1;
c=getchar();
}
while(isdigit(c))t=t*10+c-48,c=getchar();
t=f*t;
}
template <typename T,typename... Args> inline void read(T& t,Args&... args){
read(t);read(args...);
}
int n,m,vis[maxn],in[maxn],ans[maxn];
int instd[maxn],outstd[maxn];
vector<int>e[maxn];
void init(){
for(int i=0;i<=n;i++){
e[i].clear();
in[i]=0;
ans[i]=0;
}
memset(vis,0,sizeof vis);
memset(instd,0,sizeof instd);
memset(outstd,0,sizeof outstd);
}
bool top_sort(){
queue<int> q;
for(int i=1;i<=n;i++){
if(!in[i])q.push(i);
}
int tops=0;
while(!q.empty()){
int now=q.front();
q.pop();
ans[now]=++tops;
for(int i=0;i<e[now].size();i++){
int v=e[now][i];
in[v]--;
if(!in[v]){
q.push(v);
}
}
}
return tops==n?true:false;
}
int main(){
int t;
read(t);
while(t--){
read(n,m);
init();
for(int i=1;i<=m;i++){
int tmp,x,y;
read(tmp,x,y);
instd[i]=x;
outstd[i]=y;
if(tmp){
vis[i]=1;
e[x].emplace_back(y);
in[y]++;
}
}
if(!top_sort()){
puts("NO");
continue;
}
puts("YES");
for(int i=1;i<=m;i++){
if(vis[i]||ans[instd[i]]<ans[outstd[i]]){
printf("%d %d\n",instd[i],outstd[i]);
}else{
printf("%d %d\n",outstd[i],instd[i]);
}
}
}
return 0;
}