题目大意:
树的定义为:
1. 由0个、1个或多个结点和有向边组成;
2. 除了根结点入度为0,其余结点入度为1;
3. 每个点从根结点到它都可达;
现有多个测例,每个测例都给出若干条边的描述"x y",x、y为结点编号,从1开始,表示y为x的子结点,程序以两个负数结束,每个测例以"0 0"结束,要求对于每个测例判断输入的是否为一棵树。
注意:结点数在15个左右,树中所有结点的编号并不一定能组成一段连续的数!!
注释代码:
/*
* Problem ID : POJ 1308 Is It A Tree?
* Author : Lirx.t.Una
* Language : C++
* Run Time : 0 ms
* Run Memory : 152 KB
*/
#include <iostream>
#include <cstring>
#include <cstdio>
//最大结点数
#define MAXN 15
using namespace std;
char fath[MAXN];
bool vist[MAXN];//标记每个结点是否被访问过
int
find(int x) {
if ( x == fath[x] ) return x;
return fath[x] = find( fath[x] );
}
int
main() {
int t;//测例数
int x, y;//接受临时输入的结点编号
int i;//计数变量
int node;//结点总数
int edge;//边的总数
bool isTree;//标志当前是否是一棵树或森林
t = 0;
while ( scanf("%d%d", &x, &y), x >= 0 ) {//输入为负整个程序结束
//一个测例输入的开始
//输入为0表示一个测例结束
if ( !x ) {//没有任何结点,表示一棵空树
//因此也是树
printf("Case %d is a tree.\n", ++t);
continue;
}
//树非空则初始化
memset(vist, false, sizeof(vist));//每个结点都未访问过
for ( i = 0; i < MAXN; i++ ) fath[i] = i;
node = 0;
edge = 0;
isTree = true;
do {
if ( !isTree ) continue;//如果之前已经判断出不是树了,则后面的检查都可省略
if ( x == y ) {//如果结点有自反性那肯定也不是树
isTree = false;
continue;
}
//输入x y时是表示y是x的子结点的!!
//如果find(y) == y就表示y还未和任何结点合并过
//但是如果find(y) != y就表示y已经和其它结点合并过了
//由于合并操作是将子结点接在集合(树)的根结点上的
//因此find(y) != y表示y之前已经属于某棵树的子结点了,因此其入度已经为1了
//这里y又是x的子结点,因此x的入度就大于1了,因此如果find(y) != y则输入一定不是一棵树
if ( find(y) == y ) fath[y] = find(x);//将y并入,并将y接在树的根结点处
//!!注意:并查集根结点也是树的根结点
else {
isTree = false;
continue;
}
//对访问进行标记
if ( !vist[x] ) {
vist[x] = true;
node++;
}
if ( !vist[y] ) {
vist[y] = true;
node++;
}
edge++;
} while ( scanf("%d%d", &x, &y), x );//为0表示一个测例结束
printf("Case %d is ", ++t);
//如果node > edge + 1则是一个森林(多个根结点)
if ( isTree && node == edge + 1 ) puts("a tree.");
else puts("not a tree.");//森立不是树,也应该排除
}
return 0;
}
无注释代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#define MAXN 15
using namespace std;
char fath[MAXN];
bool vist[MAXN];
int
find(int x) {
if ( x == fath[x] ) return x;
return fath[x] = find( fath[x] );
}
int
main() {
int t;
int x, y;
int i;
int node;
int edge;
bool isTree;
t = 0;
while ( scanf("%d%d", &x, &y), x >= 0 ) {
if ( !x ) {
printf("Case %d is a tree.\n", ++t);
continue;
}
memset(vist, false, sizeof(vist));
for ( i = 0; i < MAXN; i++ ) fath[i] = i;
node = 0;
edge = 0;
isTree = true;
do {
if ( !isTree ) continue;
if ( x == y ) {
isTree = false;
continue;
}
if ( find(y) == y ) fath[y] = find(x);
else {
isTree = false;
continue;
}
if ( !vist[x] ) {
vist[x] = true;
node++;
}
if ( !vist[y] ) {
vist[y] = true;
node++;
}
edge++;
} while ( scanf("%d%d", &x, &y), x );
printf("Case %d is ", ++t);
if ( isTree && node == edge + 1 ) puts("a tree.");
else puts("not a tree.");
}
return 0;
}
简单入度计算:
注释代码:
/*
* Problem ID : POJ 1308 Is It A Tree?
* Author : Lirx.t.Una
* Language : C++
* Run Time : 0 ms
* Run Memory : 152 KB
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#define MAXN 15
using namespace std;
char deg[MAXN];//各个点的入度
bool vis[MAXN];
int
main() {
int t;
int u, v;
int node;
int edge;
bool isTree;
t = 0;
while ( scanf("%d%d", &u, &v), u >= 0 ) {
if ( !u ) {
printf("Case %d is a tree.\n", ++t);
continue;
}
memset(deg, 0, sizeof(deg));
memset(vis, false, sizeof(vis));
node = 0;
edge = 0;
isTree = true;
do {
if ( !isTree ) continue;
if ( u == v ) {
isTree = false;
continue;
}
if ( ++deg[v] > 1 ) {//如果入度大于1则不是树
isTree = false;
continue;
}
if ( !vis[u] ) {
vis[u] = true;
node++;
}
if ( !vis[v] ) {
vis[v] = true;
node++;
}
edge++;
} while ( scanf("%d%d", &u, &v), u );
printf("Case %d is ", ++t);
if ( isTree && node == edge + 1 ) puts("a tree.");
else puts("not a tree.");
}
return 0;
}
无注释代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#define MAXN 15
using namespace std;
char deg[MAXN];
bool vis[MAXN];
int
main() {
int t;
int u, v;
int node;
int edge;
bool isTree;
t = 0;
while ( scanf("%d%d", &u, &v), u >= 0 ) {
if ( !u ) {
printf("Case %d is a tree.\n", ++t);
continue;
}
memset(deg, 0, sizeof(deg));
memset(vis, false, sizeof(vis));
node = 0;
edge = 0;
isTree = true;
do {
if ( !isTree ) continue;
if ( u == v ) {
isTree = false;
continue;
}
if ( ++deg[v] > 1 ) {
isTree = false;
continue;
}
if ( !vis[u] ) {
vis[u] = true;
node++;
}
if ( !vis[v] ) {
vis[v] = true;
node++;
}
edge++;
} while ( scanf("%d%d", &u, &v), u );
printf("Case %d is ", ++t);
if ( isTree && node == edge + 1 ) puts("a tree.");
else puts("not a tree.");
}
return 0;
}
单词解释:
sequentially:adv, 从而,依次地
correspond:vi, 符合,相一致
arrowhead:n, 箭头
property:n, 属性
satisfy:vt, 满足,满足...(条件)
directed:adj, 定向的,有向的