#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 2e5 + 10;//
struct edge {
int to, next;
}edge[maxn];
int head[maxn], cnt;//链式int indeg[maxn], topo[maxn], tot;
void addedge(int u, int v) {
edge[++cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt;
indeg[v]++;//注意记录入度
}struct e {
int x, y;
}e[maxn];bool Topo(int n) {//拓扑排序
queue<int> q;
tot = 0;
for (int i = 1; i <= n; i++)
if (indeg[i] == 0) q.push(i);//找到入度为0的点作为起始点,入队
while (!q.empty()) {//队列为0时,即没有点的入度为0时停止循环.
int x = q.front(); q.pop();//入度为0出队
topo[x] = ++tot;//记录拓扑序,即入度为0的顺序
for (int i = head[x]; i; i = edge[i].next) {//遍历所有边
int temp = edge[i].to;
indeg[temp]--;//入度为0的所有点连接所有点入度减1
if (!indeg[temp]) q.push(temp);//如果有那个点入度为0,入队
}
}
if (tot < n) return false;//当拓扑排序结束后,如果所有点都纳入则可以拓扑,如果有环则部分点无法纳入
//如果有的点不连通或者全是由无向边连接,则入度一直为0,不会漏掉
return true;
}int main()
{
int t;
scanf("%d", &t);
while (t--) {
int n, m, tt = 0;
cnt = 0;
scanf("%d%d", &n, &m);
memset(head, 0, sizeof(head));
memset(indeg, 0, sizeof(indeg));
for (int i = 1; i <= m; i++) {
int t, x, y;
scanf("%d%d%d", &t, &x, &y);//t判断是否是由向边
if (t == 1) addedge(x, y);
else {
e[++tt].x = x;//如果是无向,保存到e中
e[tt].y = y;
}
}
if (!Topo(n)) {//判断拓扑如果有向图可以拓扑那么无向的边一定也可以加入进来变成拓扑图
//,如果有向图成环无法拓扑那么加上无向边也不可以
puts("NO"); continue;
}
puts("YES");
for (int i = 1; i <= n; i++)
for (int j = head[i]; j; j = edge[j].next)
printf("%d %d\n", i, edge[j].to);
for (int i = 1; i <= tt; i++) {
int x = e[i].x, y = e[i].y;
if (topo[x] < topo[y]) printf("%d %d\n", x, y);
else printf("%d %d\n", y, x);
}
}}
[图论DAG]CF1385E Directing Edges
于 2022-01-21 15:52:57 首次发布