UVALive 6091 Trees 并查集(水

题目链接:点击打开链接

题意:

给定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




*/


你可能感兴趣的:(UVALive 6091 Trees 并查集(水)