题目传送门
1 /*
2 题意:无向图和有向图的混合图判环;
3
4 官方题解:首先对于所有的无向边,我们使用并查集将两边的点并起来,若一条边未合并之前,
5 两端的点已经处于同一个集合了,那么说明必定存在可行的环(因为这两个点处于同一个并查集集合中,那么它们之间至少存在一条路径)
6 如果上一步没有判断出环,那么仅靠无向边是找不到环的
7 考虑到,处于同一个并查集集合中的点之间必定存在一条路径互达,因此将一个集合的点合并之后,
8 原问题等价于在新生成的有向图中是否有环
9 我们知道,有向无环图必定存在拓扑序,因此只需使用拓扑排序判定即可
10 时间复杂度O(N+M1+M2)
11
12 并查集+拓扑排序:并查集来判断无向图,拓扑排序判断有向图
13
14 另外:用读入外挂时间比scanf ()多,不清楚...
15 Accepted 5222 5007MS 45124K 2158 B G++ BH //scanf ()
16 Accepted 5222 7581MS 45116K 2158 B G++ BH //read ()
17 */
18 #include <cstdio>
19 #include <cmath>
20 #include <cstring>
21 #include <string>
22 #include <iostream>
23 #include <algorithm>
24 #include <queue>
25 #include <vector>
26 #pragma comment(linker, "/STACK:102400000,102400000")
27 using namespace std;
28
29 const int MAXN = 1e6 + 10;
30 const int INF = 0x3f3f3f3f;
31 int ans[MAXN], in[MAXN];
32 int rt[MAXN];
33 vector<int> G[MAXN];
34 int n, m1, m2;
35
36 inline int read(void)
37 {
38 int x = 0, f = 1; char ch = getchar ();
39 while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar ();}
40 while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar ();}
41 return x * f;
42 }
43
44 bool TopoSort(void)
45 {
46 memset (in, 0, sizeof (in));
47 for (int i=1; i<=n; ++i)
48 for (int j=0; j<G[i].size (); ++j) in[G[i][j]]++;
49
50 queue<int> Q; int cnt = 0;
51 for (int i=1; i<=n; ++i) {if (!in[i]) Q.push (i);}
52
53 while (!Q.empty ())
54 {
55 int u = Q.front (); Q.pop ();
56 ans[++cnt] = u;
57 for (int j=0; j<G[u].size (); ++j)
58 {
59 int v = G[u][j];
60 in[v]--;
61 if (!in[v]) Q.push (v);
62 }
63 }
64
65 if (cnt == n) return false;
66 else return true;
67 }
68
69 int Find(int x)
70 {
71 return (rt[x] == x) ? rt[x] : rt[x] = Find (rt[x]);
72 }
73
74 void Union(int x, int y)
75 {
76 x = Find (x); y = Find (y);
77 if (x < y) rt[x] = y;
78 else rt[y] = x;
79 }
80
81 bool same(int x, int y)
82 {
83 return (Find (x) == Find (y)) ? true : false;
84 }
85
86 int main(void) //赛码 1009 Exploration
87 {
88 //freopen ("I.in", "r", stdin);
89
90 int t;
91 scanf ("%d", &t);
92 while (t--)
93 {
94 scanf ("%d%d%d", &n, &m1, &m2);
95
96 for (int i=1; i<=n; ++i) rt[i] = i;
97 for (int i=1; i<=n; ++i) G[i].clear ();
98
99 bool ok = false; int u, v;
100 for (int i=1; i<=m1; ++i)
101 {
102 scanf ("%d%d", &u, &v);
103 //u = read (); v = read ();
104 //G[u].push_back (v);
105 if (same (u, v) == true) ok = true;
106 else Union (u, v);
107 }
108 for (int i=1; i<=m2; ++i)
109 {
110 int u, v;
111 scanf ("%d%d", &u, &v);
112 //u = read (); v = read ();
113 if (same (u, v) == true) ok = true;
114 if (ok) continue;
115 G[u].push_back (v);
116 }
117
118 if (ok) {puts ("YES"); continue;}
119 if (TopoSort () == true) puts ("YES");
120 else puts ("NO");
121 }
122
123 return 0;
124 }