【拓扑排序】【好题】E. Directing Edges
题意
给你一些点和边,边中既有有向边和无向边,求通过对所有无向边赋予方向后,这张图是否能构成一张有向无环图(DAG)。
思路分析
由于没有办法更改已经形成的有向边的方向,所以如果图中的有向边已经形成了环,那么就很明确的无法构成一张DAG图了。
而对于无向边的图我们可以把它们先看成是一个个孤立的点,又结合拓扑排序及拓扑序标记的性质,我们可以知道这些点是伙同有向边中入度为0的点在第一轮的时候就加入到队列中去。也就是它们的拓扑序肯定是小于第二轮加入的点,而我们又知道在拓扑排序中,一条有向边的起点的拓扑序是要小于这条有向边的拓扑序的。
且若在这张图存在环,也就是说这张图中存在一些点它的入度无法通过拓扑排序的消解的过程变成0,因为只需要将拓扑排序实际处理的点数和总点数进行一个比较就可以知道这张图中是否具有环。
#include <bits/stdc++.h>
#define pii pair<int,int>
#define FI first
#define SE second
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N = 2E5+100,M = 2E5+100;
struct edge{
int u,v,ne;
}edges[M];
int h[N],idx;
void add(int u,int v)
{
edges[idx] = {u,v,h[u]};
h[u] = idx++;
}
int n,m;
int indu[N],order[N],time_stamp = 0;
void topo()
{
queue<int> q;
for(int i=1;i<=n;i++)
if(!indu[i]) q.push(i);
while(q.size())
{
int u =q.front();
q.pop();
order[u] = ++time_stamp;
for(int i=h[u];~i;i=edges[i].ne)
{
int v = edges[i].v;
indu[v]--;
if(!indu[v])
q.push(v);
}
}
}
vector<pii> ans;
void init()
{
ans.clear();
for(int i=1;i<=n;i++)
h[i] = -1,order[i] = indu[i] = time_stamp = idx = 0;
}
int main()
{
int T = read();
while(T--)
{
n = read(),m = read();
init();
for(int i = 1;i <= m;i++)
{
int f = read(), u = read(), v = read();
ans.push_back({u,v});
if(f) add(u,v),indu[v]++;
}
topo();
if(time_stamp<n)
printf("NO\n");
else
{
printf("YES\n");
for(int i=0;i<ans.size();i++)
{
int u = ans[i].FI, v = ans[i].SE;
if(order[u]>order[v])
swap(u,v);
printf("%d %d\n",u,v);
}
}
}
return 0;
}