原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1232
CSUST链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=19760#problem/C
4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0
1 0 2 998Huge input, scanf is recommended.HintHint
算法:并查集。
思路:和前面做的那道题目hdu 1878 欧拉回路差不多。
用并查集判断出共有几个连通分量,然后再加上未连入一条边的点【即入度为0】的
个数,最后减一即可。
#include<cstdio> #include<cstring> const int maxn = 1000+10; int p[maxn]; //存父节点 int r[maxn]; //存度 int n, m; int find(int x) { return x == p[x] ? x : p[x]=find(p[x]); } void Union(int x, int y) //合并 { x = find(x); //注意:开始写成了x = p[x]一路WA。。。 y = find(y); if(x == y) return; else { p[x] = y; } } int main() { while(scanf("%d", &n) != EOF) { if(n == 0) break; scanf("%d", &m); memset(r, 0, sizeof(r)); //初始化度为0 for(int i = 1; i <= n; i++) //开始自己是自己的根 { p[i] = i; } for(int i = 1; i <= m; i++) { int x, y; scanf("%d%d", &x, &y); r[x]++; r[y]++; Union(x, y); //由于边比较多,所以每读入一条边就合并一次 } int root = 0; for(int i = 1; i <= n; i++) { if(r[i] && i == p[i]) //判断共有几个联通分量子集(集合元素>1) { root++; } } for(int i =1; i<=n; i++)//从未连入边的城市 if(!r[i]) root++; printf("%d\n", --root); } return 0; }