hdu 1116 Play on Words(欧拉图判断模板)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1116(并查集+欧拉通路的判断,模板!!!

思路:这个题目用到了并查集的操作,先将所有的点弄到一个或者多个集合中。并查集处理的过程中,将被处理的点标记一下,表示已经被访问过。过程中要统计各个点的出度和入度。

一般判断欧拉回(通)路的过程:

1)这个图必须是连通的,即根结点只有一个。如果不是,直接结束本次算法

2)如果这个图是连通的,判断每个结点的入度和出度情况。

    如果这个图是欧拉路,则每个顶点的出度等于入度。即out[i] = in[i]

如果这个图是半欧拉图,则起点的出度比入度大1,终点的入度比出度大1.其余顶点的出度等于入度。

如果满足上述条件,就可以将所有单词链接起来,否则不能。

当然,在判断出度入度的时候还有一点需要注意,那就是除了起点终点以外的顶点,出度必须等于入度(出度入度可以同时为2,即环),但是起点和终点必须保证出度和入度之差为1。


代码:

#include<iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=30;
int pre[maxn],in[maxn],out[maxn];//in  out 分别为出度和入度
bool visit[maxn];//用来标记点是否被访问到

void buildset()//初始化
{
    for(int i=0;i<maxn;i++){
        pre[i]=i;
        in[i]=out[i]=0;
        visit[i]=false;
    }
}
int find(int x)
{
    int p,temp;
    p=x;
    while(x!=pre[x]) x=pre[x];

    while(p!=x){
        temp=pre[p];
        pre[p]=x;
        p=temp;
    }
    return x;
}

void join(int x,int y)
{
    int p=pre[x];
    int q=pre[y];
    if(p!=q) pre[q]=p;
}
int main()
{
    int T;scanf("%d",&T);while(T--){
        int start,end;//作为一个字母的开头与结尾
        buildset();
        char str[1010];//带输入的字符串
        int wordnum,len;//单词的数量以及某个单词的长度
        int innum,outnum;//判断出度和入度不相等点的个数
        int root;//根节点的个数
        innum=outnum=root=0;
        bool flag=true,flag1=true;//用来盘肚腩连通性
        scanf("%d",&wordnum);
        for(int i=1;i<=wordnum;i++){
            scanf("%s",str);
            len=strlen(str);
            start=str[0]-'a'+1;
            end=str[len-1]-'a'+1;
            visit[start]=true,visit[end]=true;
            out[start]++;
            in[end]++;
            join(start,end);
        }

        for(int i=1;i<maxn;i++){
            if(visit[i]){//如果这个点被访问到,根据题目要求肯定只便利被访问到的点
                    if(pre[i]==i) root++;
                    if(out[i]!=in[i]){
                        if(in[i]-out[i]==1)
                            innum++;
                        else if(out[i]-in[i]==1)
                            outnum++;
                        else
                            flag1=false;//flag1 用来判断出度与入度之差,不相等的情况下只可能差1
                    }
                    if(root>1){
                        flag=false;//flag用来判断是否只有一个根节点
                        break;
                    }
            }
        }
        if((flag && innum == 0 && outnum == 0 && flag1) || (flag && innum == 1 && outnum == 1 && flag1))//出度与入度和一样,以及出度入度差一的情况
            printf("Ordering is possible.\n");
        else
            printf("The door cannot be opened.\n");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值