并查集运用,最后那一步并查集判断个人觉得有点儿小微妙。
/**State: HDU3560 234MS 1812K 1260 B C++ *题目大意:* 给定一个无向图,求无向图的连通分量的数量,还有连通分量是一个环的* 数量。*解题思路:* 各种解法都行,用并查集比较简单。还可以用广搜,还可以用深搜,但是写起来麻烦。* 而且广搜跟深搜的时间复杂度是O(v + e),但是并查集的时间复杂度通过有效地修改* 可以改至接近线性,采用启发式合并还有路径压缩,还可以到达O(1),优雅至极。*题目困惑:* 用并查集开始写,应该是很清晰的思路的,结果因为初始化,各种TLE.怎么都没有想到* 是因为初始化导致的TLE,白白贡献了4~5个TLE,囧。不过想不通100000的点,我初始化* 哪里会TLE啦。以后要多注意下初始化了。多用脑袋跟时间还内存斤斤计较哈。*/
View Code
#includeusing namespace std;const int MAXN = 100005;typedef struct _node{ int p, rank;}N;N uqSet[MAXN];int vst[MAXN], du[MAXN];void init(int n){ for(int i = 0; i < n; i++) { du[i] = vst[i] = 0; uqSet[i].p = i; uqSet[i].rank = 0; }}int findSet(int x){ int f = x, t; while(x != uqSet[x].p) x = uqSet[x].p; while(f != x) { t = uqSet[f].p; uqSet[f].p = x; f = t; } return x;}void Union(int x, int y){ x = findSet(x); y = findSet(y); if(x == y) return ; if(uqSet[x].rank > uqSet[y].rank) { uqSet[y].p = x; } else { if(uqSet[x].rank == uqSet[y].rank) uqSet[y].rank++; uqSet[x].p = y; }}int main(void){#ifndef ONLINE_JUDGE //freopen("in.txt", "r", stdin);#endif int n, m; while(scanf("%d %d", &n, &m), n || m) { init(n); int u, v; for(int i = 0; i < m; i++) { scanf("%d %d", &u, &v); du[u]++, du[v]++; Union(u, v); } int com = 0; int reduce = 0; for(int j = 0; j < n; j++) { if(findSet(j) == j) com++; if(vst[findSet(j)] == 0 && du[j] != 2) { vst[findSet(j)] = 1; reduce++; } } printf("%d %d\n", com, com - reduce); } return 0;}