CF-1385E Directing Edges

题意

给定一个由有向边与无向边组成的图,现在需要你把所有的无向边变成有向边,使得形成的图中没有环

如果可以做到请输出该图,否则直接输出"NO"。

分析

我们先只连接有向边,然后做一遍拓扑排序,如果失败了,就说明有环,输出 “NO”。

然后处理剩下的无向边。对于无向边 $(u, v)$,如果 $u$ 的拓扑序小于 $v$,那么令这条边的方向是 $u\rightarrow v$。否则,方向就是 $v\rightarrow u$。因为这条边是从拓扑序小的点指向拓扑序大的点,所以必然不会形成环。

RECORD

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>

using namespace std;
const int MAXN = 200005;
int n, m;
vector<int> G[MAXN];
int c[MAXN], topo[MAXN], id[MAXN], t, bn, x[MAXN], y[MAXN];
bool dfs(int u) {
  c[u] = -1;
  for (auto v : G[u]) {
    if (c[v] < 0)
      return false;
    else if (c[v] == 0 && !dfs(v))
      return false;
  }
  c[u] = 1;
  topo[--t] = u;
  id[u] = t;
  return true;
}
bool toposort() {
  t = n;
  memset(c, 0, sizeof(c));
  memset(id, 0, sizeof(id));
  memset(topo, 0, sizeof(topo));
  for (int i = 1; i <= n; i++)
    if (!c[i])
      if (!dfs(i)) return false;
  return true;
}
int main() {
  ios::sync_with_stdio(false);
  int t;
  cin >> t;
  while (t--) {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) G[i].clear();
    bn = 0;
    for (int i = 0; i < m; i++) {
      int ti, tx, ty;
      cin >> ti >> tx >> ty;
      if (ti == 0) {  // 无向
        x[++bn] = tx;
        y[bn] = ty;
      } else {
        G[tx].push_back(ty);
      }
    }
    if (!toposort()) {
      cout << "NO\n";
      continue;
    }
    cout << "YES\n";
    for (int i = 1; i <= bn; i++) {
      if (id[x[i]] <= id[y[i]])
        cout << x[i] << " " << y[i] << endl;
      else
        cout << y[i] << " " << x[i] << endl;
    }
    for (int i = 1; i <= n; i++) {
      for (auto j : G[i]) { cout << i << " " << j << endl; }
    }
  }
  return 0;
}