poj 1308 is it a tree?(图的性质||基础并查集) (同hdu 1272 小希的迷宫 )

本文介绍了通过并查集和图的性质两种方法来判断一个给定的图是否构成一棵树。并查集方法关注节点连接状态,避免环路形成;而图的性质方法则基于节点数与边数的关系进行判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://poj.org/problem?id=1308#top (写这题的时候杭电进不去)
题意: 问你输入的一个图是不是一个树,输入n和m表示n和m是连同的,输入0 0表示这个图已经输完可以进行判断,输入-1 -1表示这个程序运行结束。不过写这题的要注意:空树也是树,死人也是人
思路:这题有两个解法,先写并查集的解法,一般人拿到题目分析的时候都是从并查集入手,但是第二个方法就相对来说就比较简单了。
一、基础并查集
并查集三步:根节点,find,unite
然后考虑题目要求:
1、判断是否成环,这个时候就可以利用临近成环的那一刻出现的情况,要成环的接口处两个节点的根节点相同
2、空树,只要知道了这点应该不难判断
3、未连同,如果出现两个及以上的当标记位置不为零时,节点和父节点一样就处于未连同状态

代码:

#include<cstdio>
#include<cstring>
using namespace std;
const int max=50050;
int flag[max],pa[max],t;

inline void  init(){
    for(int i=1;i<max;i++)
     pa[i]=i;
}

int find(int x){
    if(x!=pa[x]) pa[x]=find(pa[x]);
    return pa[x];
}

void unite(int x,int y){
    int fx=find(x);
    int fy=find(y);
    if(fx==fy){
    t=1;return ;    
    }
    flag[x]=flag[y]=1; 
    pa[y]=fx;
}

int main(){
    int n,m,l=1,ma,mi;
    t=0;
    memset(flag,0,sizeof(flag));
    init();ma=mi=0;  
    while(~scanf("%d%d",&n,&m)){
      if(n>ma) ma=n;if(m>ma) ma=m;
      if(n<mi) mi=n;if(m<mi) mi=m;
      if(n==-1&&m==-1) break;
      if(n==0&&m==0){
        int p=0;
        for(int i=mi;i<=ma;i++)
         if(flag[i]!=0&&i==pa[i]) p++;
        if(p>1) t=1; 
        memset(flag,0,sizeof(flag));
        if(t==0) printf("Case %d is a tree.\n",l);
        else printf("Case %d is not a tree.\n",l);
        init();l++;t=ma=mi=0;
        continue; 
      }
      if(flag[n]==0&&flag[m]!=0) unite(m,n);
      else unite(n,m);
    } 
    return 0;
}

二、图的性质
这个也算是这题当中树的性质吧。我们可以把这个树看成图(怎么写的那么便扭呢。。。),这个图由节点(dian)和边(bian)组成,当这个图输完的时候
dian>bian+1,说明这个图还有的位置是未连同的;
dian<bian+1 , 说明这个图里成环;
所以判断成树的条件就bian+1=dian;
又因为空树的存在,加上判断条件bian=0;

代码:

#include<cstdio>
#include<cstring>
const int max=50500;

int main(){
    int flag[max],dian,bian,max,min;
    dian=bian=min=max=0;
    int n,m,l=1;
    memset(flag,0,sizeof(flag));
    while(~scanf("%d%d",&n,&m)){
        if(n==-1&&n==-1) break;
        if(n==0&&m==0)
        {
            int sum=0;
            memset(flag,0,sizeof(flag));
            if(dian==bian+1||bian==0) printf("Case %d is a tree.\n",l);
            else printf("Case %d is not a tree.\n",l);
            l++;bian=dian=0;
            continue; 
        }
        if(n>max) max=n;if(n<min) min=n;
        if(m>max) max=m;if(m<min) min=m;
        if(flag[n]==0) flag[n]=1,dian++;
        if(flag[m]==0) flag[m]=1,dian++;
        bian++;         
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值