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