思路:拓扑序、有向图判环。
有向图判环大家都很熟悉,就是跑一边拓扑排序,看最终加入队列的点数是否等于总点数。
第二个是给环添加方向的做法。
这让我想起了学网络流时的dinic算法。也就是选取一点dfs,得出所有点的深度,然后路线只能从浅向深移动,这样避免成环,我的思路正是受这启发。
这里就不用多写dfs了,用拓扑序(可以理解为深度)解决即可。
code:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200010
int ton[MAXN],in[MAXN];//存拓扑序和入度
struct node{
int x,y;
};int n,m;
queue<int>q;
vector<node>ask;//存无向边
vector<node>ans;//存结果
vector<int>e[MAXN];//存边
bool topsort()//拓扑排序
{
int num = 0;
for(int i=1;i<=n;i++)if(!in[i])q.push(i);
while(!q.empty())
{
int x = q.front();
q.pop();
num++;
ton[x] = num;
for(int i=0;i<e[x].size();i++)
{
in[e[x][i]]--;
if(!in[e[x][i]])q.push(e[x][i]);
}
}
return num==n;//判图是否成环
}
int main()
{
int t;
cin>>t;
while(t--)
{
ask.clear();
ans.clear();
memset(e,0,sizeof e);
memset(ton,0,sizeof ton);
memset(in,0,sizeof in);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int s,x,y;
scanf("%d%d%d",&s,&x,&y);
if(s==1){
in[y]++;
e[x].push_back(y);
ans.push_back((node){
x,y});
}
if(s==0)
{
ask.push_back((node){
x,y});
}
}
if(!topsort()){
puts("NO");
continue;
}
for(int i=0;i<ask.size();i++)
{
node p = ask[i];
if(ton[p.x]>ton[p.y])//根据深度询问
{
ans.push_back((node){
p.y,p.x});
}else ans.push_back((node){
p.x,p.y});
}
puts("YES");
for(int i=0;i<ans.size();i++)
printf("%d %d\n",ans[i].x,ans[i].y);
}
}