【HDU1272】小希的迷宫
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1272
【分析】每组数据中输入多组两个整数代表通道连接的两个房间的编号,房间的编号至少为1。以0,0,这组数据输入结束,以-1,-1测试结束。条件:保证图是连通的,且连通分量为1( 即从一点可以到任意一点 ),不存在环(包括自环)
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100000 + 10;
int par[N]; //父节点
int vis[N]; //标记这点已经加入了最小生成树
int flag;
int find(int x) //查找父节点
{
int p = x;
while (par[p] != p)
p = par[p];
int i = x;
int j;
while (i != p)
{
j = par[i];
par[i] = p;
i = j;
}
return p;
}
void unionset(int x, int y) //连接两个房间
{
if ((x = find(x)) == (y = find(y))) //父节点相同证明已连接,此时不需要连接
flag = 0;
else
par[y] = x; //不同的话,证明还未连接
}
void init()
{
for (int i = 0; i<N; i++)
{
par[i] = i; //父节点为自己
vis[i] = 0; //每个点都还未遍历
}
}
int main()
{
int r1, r2;
while (scanf("%d%d", &r1, &r2) != EOF) //仅对第一对房间输入
{
if (r1 == 0 && r2 == 0) //即使一开始输入00,也是对的
{
printf("Yes\n");
continue;
}
init();
if (r1 == -1 && r2 == -1)
break;
unionset(r1, r2); //连接第一对房间号
flag = 1; //第一对房间被连接
vis[r1] = 1;
vis[r2] = 1; //已连接做标记
while (scanf("%d%d", &r1, &r2) && r1 && r2) //对后面的房间输入做判断
{
unionset(r1, r2);
vis[r1] = 1;
vis[r2] = 1;
}
if (flag == 0) //若有成环,则输出NO
{
printf("No\n");
continue;
}
else
{
int sum = 0;
for (int i = 0; i <= N; i++)
{
if (vis[i] == 1 && par[i] == i) //父节点为同一个
sum++;
}
if (sum == 1) //刚好满足条件
printf("Yes\n");
else //无环 但是不能完全连通
printf("No\n");
}
}
return 0;
}
【HDU1325】Is It A Tree?
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1325
【分析】这两题其实很像,但是唯一的区别是,上题是无向,这题是有向的。条件:1,无环;2,除了根,所有的入度为1,根入度为0。
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100000 + 10;
int par[N];
int vis[N];
int flag;
int find(int x)
{
if (par[x] == x)
return x;
else
return find(par[x]);
}
void unionset(int x, int y)
{
int xx = find(x);
int yy = find(y);
if (xx == yy)
flag = 0;
else
par[y] = x;
}
void init()
{
for (int i = 0; i<N; i++)
{
par[i] = i;
vis[i] = 0;
}
}
int main()
{
int k = 0;
int r1, r2;
while (scanf("%d%d", &r1, &r2) != EOF) //仅对第一对房间输入
{
k++;
flag = 1;
if (r1<0 && r2<0)
break;
if (r1 == 0 && r2 == 0) //即使一开始输入00,也是对的
{
printf("Case %d is a tree.\n", k);
continue;
}
init();
unionset(r1, r2); //第一对房间
vis[r1] = 1;
vis[r2] = 1;
par[r2] = r1; //只能从r1 到 r2
while (scanf("%d%d", &r1, &r2) && r1 && r2) //对后面的房间输入做判断
{
unionset(r1, r2);
vis[r1] = 1;
vis[r2] = 1;
}
if (flag == 0) //有环
{
printf("Case %d is not a tree.\n", k);
continue;
}
else
{
int sum = 0;
for (int i = 0; i <= N; i++)
{
if (vis[i] == 1 && par[i] == i) //存在这个房间并且父节点是自己
sum++;
if (sum>1) //出现有不同的根节点,证明有不同的的树
break;
}
if (sum>1)
printf("Case %d is not a tree.\n", k);
else
printf("Case %d is a tree.\n", k);
}
}
return 0;
}