1116: [POI2008]CLO

1116: [POI2008]CLO

https://lydsy.com/JudgeOnline/problem.php?id=1116

分析:

  单独考虑每个联通块的情况。
  设这个联通块里有n个点,那么至少有n-1条边了。
  如果每个点入度都为1,那么就要求至少有n条边(其实就是基环树),大于n条边可以不选。
  所以有:如果一个联通块是可行的,必须满足存在大于等于点数条边。
  所以并查集维护加边的过程。
    1、出现了环,那么这个联通块就合法了。
    2、合并两个联通块,只要一个联通块里合法就行。(一个合法了,另一个也至少存在n-1条边,那么加入这条后,刚好满足了)。
代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<cmath>
 6 #include<cctype>
 7 #include<set>
 8 #include<queue>
 9 #include<vector>
10 #include<map>
11 using namespace std;
12 typedef long long LL;
13  
14 inline int read() {
15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
17 }
18  
19 const int N = 200005; 
20  
21 int fa[N], g[N];
22  
23 int find(int x) {
24     return x == fa[x] ? x : fa[x] = find(fa[x]);
25 } 
26  
27 int main() {
28     int n = read(), m = read();
29     for (int i = 1; i <= n; ++i) fa[i] = i;
30     while (m --) {
31         int u = read(), v = read();
32         u = find(u), v = find(v);
33         if (u == v) g[u] = 1;
34         else fa[u] = v, g[v] |= g[u];
35     }
36     for (int i = 1; i <= n; ++i) 
37         if (!g[find(i)]) return puts("NIE"), 0;
38     puts("TAK");
39     return 0;
40 }
41 
原文地址:https://www.cnblogs.com/mjtcn/p/10045619.html