胡编乱造的定理一:给定一个无向图,对边标记方向,则一定可以有方法使得图中无环。
当时想到的做法是:先将有向边进行拓扑排序,根据定理一,如果此时出现环那么就puts(“NO”),否则就根据之前拓扑排序得到的拓扑序,由小到大连边。因为我们知道,DAG中均是由拓扑序小的点连向拓扑序大的点。
按照拓扑序的大小,对无向图标记方向,貌似之前已经做到过一次了。希望下次类似的题能想到这个方法吧。
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int T,n,m,opt[N],u[N],v[N];
int du[N],dep[N];
bool vis[N];
int cnt,head[N];
struct edge{int next,to;}e[N];
inline void add(int u,int v)
{
cnt++;
e[cnt].next=head[u];
e[cnt].to=v;
head[u]=cnt;
}
queue<int>q;
int main(){
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
cnt=0;
for (register int i=1; i<=n; ++i) head[i]=0;
for (register int i=1; i<=n; ++i) vis[i]=false;
for (register int i=1; i<=n; ++i) du[i]=0;
for (register int i=1; i<=m; ++i)
{
scanf("%d%d%d",&opt[i],&u[i],&v[i]);
if (opt[i]) add(u[i],v[i]),du[v[i]]++;
}
for (register int i=1; i<=n; ++i) if (!du[i]) q.push(i),vis[i]=true;
int tot=0;
while (q.size())
{
int u=q.front(); q.pop();
dep[u]=++tot;
for (register int i=head[u]; i; i=e[i].next)
{
du[e[i].to]--;
if (!du[e[i].to]) q.push(e[i].to),vis[e[i].to]=true;
}
}
bool jay=true;
for (register int i=1; i<=n; ++i) if (du[i]) {jay=false; break;}
if (!jay) {puts("NO"); continue;}
puts("YES");
for (register int i=1; i<=m; ++i)
{
if (!opt[i])
{
if (dep[u[i]]<dep[v[i]]) printf("%d %d\n",u[i],v[i]);
else printf("%d %d\n",v[i],u[i]);
}
else
{
printf("%d %d\n",u[i],v[i]);
}
}
}
return 0;
}