题意:输入多个有向边,a b代表一条从a指向b的有向边,0 0表示1个测例的结束,-1 -1表示全部测例的结束。判断输入的边是否构成了一个有向树。
题解:并查集
1.这个就直接裸并查集就可以了。
2.注意输入坑点:1 1这种自环不是树,只输入0 0这种是没有结点的树。
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#define N 1000005
using namespace std ;
int pre[N] ;
int n , m ;
vector <int> room ;
bool flag ;
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)
{
flag = 0 ;
return ;
}
pre[v] = u ;
}
int main()
{
int i , j , k ;
int p , q ;
int ans , cnt = 0 ;
int t ;
bool vis[N] ;
while(scanf("%d%d" , &p , &q) && !(p < 0 && q < 0))
{
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("Case %d is a tree.\n" , ++cnt) ;
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) || pre[q] != q)//后一个判断是入度为1,无法增加入度
{
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("Case %d is a tree.\n" , ++cnt) ;
else
printf("Case %d is not a tree.\n" , ++cnt) ;
}
}