题目链接:点击打开链接
题意:
给定n个点m条边的无向图。
问这个图里有几棵树
(即环不算树,一个连通块若有a个点,则只能有a-1条边)
思路:
并查集
对每条边进行判断,若这条边连接的2个点是已经在同一个连通块里了,那么这个连通块就不是树,标记掉就可以了
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <bits/stdc++.h> template <class T> inline bool rd(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return 0; while (c != '-' && (c<'0' || c>'9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return 1; } template <class T> inline void pt(T x) { if (x <0) { putchar('-'); x = -x; } if (x>9) pt(x / 10); putchar(x % 10 + '0'); } using namespace std; typedef long long ll; const int N = 505; int f[N]; bool no[N]; int find(int x){ return x == f[x] ? x : f[x] = find(f[x]);} void Union(int x, int y){ int fx = find(x), fy = find(y); if(fx == fy) { no[fx] = no[fy] = 1; return ; } if(fx > fy) swap(fx, fy); f[fx] = fy; } int n, m; int main(){ int Cas = 1, u, v; while (cin >> n >> m, n+m){ memset(no, 0, sizeof no); for(int i = 1; i <= n; i++)f[i] = i; while(m --){ rd(u); rd(v); Union(u, v); } for(int i = 1; i <= n; i++)find(i); for(int i = 1; i <= n; i++) if(no[i])no[f[i]] = 1; int ans = 0; for(int i = 1; i <= n; i++) if(no[f[i]] == 0) { ans ++; no[f[i]] = 1; } printf("Case %d: ", Cas++); if(ans == 0)puts("No trees."); else if(ans == 1) puts("There is one tree."); else printf("A forest of %d trees.\n",ans); } return 0; } /* 10 0 10 1 1 2 10 2 1 2 2 1 */