题意:给出若干个无向边,问是否是一棵树。
题解:并查集
1.并查集。(1)若新加边的两个端点有共同的根节点,那么假如这条边后就成环。
(2)若加入边过少会产生多棵树。
2.输入说明的是:每个测例以0 0结束,且点编号从1开始。意思是加入这个测例有点那么至少为1,可以没有房间,即直接0 0结束。在代码中已标注。这真是个坑点!!!!!!
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#define N 100005
using namespace std ;
int pre[N] ;
int n , m ;
vector <int> room ;
int find(int x)
{
int temp ;
temp = x ;
while(pre[x] != x)
x = pre[x] ;
if(pre[temp] != x) // 压缩路径,提高效率。
pre[temp] = x ; // 压缩路径就是把每个结点直接指向根节点,避免重复向上查找
return x ;
}
void join(int a , int b)
{
int i , j ;
int u , v ;
int dis ;
u = find(a) ;
v = find(b) ;
if(u == v)
return ;
pre[u] = v ;
}
int main()
{
int i , j , k ;
int p , q ;
int ans ;
int t ;
bool flag ;
bool vis[N] ;
while(scanf("%d%d" , &p , &q) && !(p == -1 && q == -1))
{
memset(vis , 0 , sizeof(vis)) ;
flag = 1 ;
for(i = 1 ; i <= N - 5 ; i ++)
pre[i] = i ;
join(p , q) ;
room.clear() ;
if(!vis[p])
{
vis[p] = 1 ;
room.push_back(p) ;
}
if(!vis[q])
{
vis[q] = 1 ;
room.push_back(q) ;
}
if(p == 0 && q == 0)//输入坑点!!!!!!
{
printf("Yes\n") ;
continue ;
}
while(scanf("%d%d" , &p , &q) && !(p == 0 && q == 0))
{
if(!vis[p])
{
vis[p] = 1 ;
room.push_back(p) ;
}
if(!vis[q])
{
vis[q] = 1 ;
room.push_back(q) ;
}
if(!flag)
continue ;
if(find(p) == find(q))
{
flag = 0 ;
continue ;
}
join(p , q) ;
}
ans = 0 ;
for(i = 0 ; i < room.size() ; i ++)
if(pre[room[i]] == room[i])
ans ++ ;
if(flag && ans == 1)
printf("Yes\n") ;
else
printf("No\n") ;
}
}