题目链接:http://poj.org/problem?id=1308。
思路:这道题目要求判断所给有向图是否为一棵树(树可以为空),运用并查集来判断加入一条边后是否符合一棵树的性质,具体判断见下面代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 100
using namespace std;
int prev[MAXN], rank[MAXN], nodeExist[MAXN], edgeCnt, valid;
void init() {
for (int i = 0; i < MAXN; i++) prev[i] = i;
memset(rank, 1, sizeof(rank));
memset(nodeExist, 0, sizeof(nodeExist));
edgeCnt = 0;
valid = 1;
}
int find(int s) {
int root = s;
while (prev[root] != root) root = prev[root];
while (prev[s] != root) {
int temp = prev[s];
prev[s] = root;
s = temp;
}
return root;
}
void Union(int start, int end) {
int s = find(start);
int e = find(end);
if (s == e) {
valid = 0;
return;
}
edgeCnt++;
if (rank[s] < rank[e]) {
prev[s] = e;
rank[e] += rank[s];
}
else {
prev[e] = s;
rank[s] += rank[e];
}
}
int main() {
int start, end;
int cnt = 1, flag = 1;
init();
while (1) {
cin >> start >> end;
flag = 1;
if (start == -1 || end == -1) break;
if (start == 0 || end == 0) {
//process
int nodeCnt = 0;
for (int i = 0; i < MAXN; i++) {
if (nodeExist[i]) nodeCnt++;
}
if (!valid || nodeCnt && (nodeCnt != edgeCnt+1)) {
printf("Case %d is not a tree.\n", cnt);
}
else {
printf("Case %d is a tree.\n", cnt);
}
cnt++;
init();
flag = 0;
}
if (flag) {
if (start == end) valid = 0;
nodeExist[start] = nodeExist[end] = true;
Union(start, end);
}
}
return 0;
}
参考链接:并查集算法原理和改进。
由于题目测试集中所给出的数据所构成的图是一个连通图,也就是只有一个连通分量,那么可以依据一棵树中只有一个根节点(空树除外)以及除根节点外其余节点有且只有一个入度来判断。如果给出的测试集中含有多个连通分量并且存在一个连通分量中有环,那么这个方法就行不通了,这种情况可以利用上面所讲述的并查集来进行判断。最后空树也是一棵树。代码实现如下:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 105;
int node[maxn][2], start, end, cnt, nodeCnt;
int main(){
//init
cnt = 1;
nodeCnt = 0;
memset(node, 0, sizeof(node));
while (cin >> start >> end) {
if (start == -1 || end == -1) break;
if (start == 0 || end == 0) {
bool isTree = true;
int root = 0;
for (int i = 1; i < maxn; i++) {
if (node[i][0]) {//check whether i is in tree
if (!node[i][1]) {
if (!root) root = 1;
else {
isTree = false;
break;
}
} else if (node[i][1] > 1) {
isTree = false;
break;
}
nodeCnt++;
}
}
if ((root && isTree) || nodeCnt == 0) printf("Case %d is a tree.\n", cnt++);
else printf("Case %d is not a tree.\n", cnt++);
memset(node, 0, sizeof(node));
nodeCnt = 0;
}
node[start][0] = 1;
node[end][0] = 1;
node[end][1]++;
}
return 0;
}