HDU 1116 Play on Words

本文介绍了一道关于单词接龙的问题,通过构建有向图并利用并查集来判断是否能形成欧拉回路或路径。文章详细解释了算法思路,并给出了完整的C++代码实现。

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1116

题目意思:给出一些单词,玩单词接龙,如果能用完所有单词,则输出Ordering is possible.,否则输出The door cannot be opened.

算法分析:其实每个单词有用的部分只有首尾字母,每个单词相当于首字母指向未字母的一条有向边,一种可能是刚好是欧拉回路,另外一种可能就是刚好有一条这样的路径覆盖了所有单词。

光判断所有单词是否能组成欧拉回路或者路径是不够的,因为并不能保证只组成了一个欧拉回路或路径。所以,首先我们要检测所有单词参与构造路径是否在一个集合中。故此时用并查集实现,如果最后的集合总数大于1,那么这些单词比如不可能组成一条路。

在确定只有一个集合之后,我们只需判断,这条路是欧拉回路还是只是一条路径还是其他情况,如果是欧拉回路,那么所有点的入度等于出度,如果是一条路径,那么除起点和终点,其它点的入度也一定等于出度。其它情况都不可能用完所有单词。

下面是AC代码:

#include<iostream>
using namespace std;
const int maxn=205;
int fa[maxn],in[maxn],out[maxn],vis[maxn],p[maxn];
int Find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=Find(fa[x]);
}
void Merge(int x,int y)
{
    x=Find(x);
    y=Find(y);
    if(x!=y) fa[y]=x;
}
int main()
{
    int t,n;
    string s;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=0;i<maxn;i++) vis[i]=0,in[i]=0,out[i]=0,fa[i]=i;
        while(n--)
        {
            cin>>s;
            char l=s[0],r=s[s.size()-1];
            Merge(l,r);
            in[r]++;
            out[l]++;
            vis[l]=1;
            vis[r]=1;
        }
        int cnt=0;
        for(int i=0;i<maxn;i++)
            if(fa[i]==i&&vis[i]) cnt++;
        if(cnt>1)//连通分支大于1,则不可能有欧拉回路
        {
            cout<<"The door cannot be opened."<<endl;
            continue;
        }
        int j=0;
        for(int i=0;i<maxn;i++)
            if(in[i]!=out[i]) p[j++]=i;//保存入度和出度不相等的点
        if(j==0)//如果不存在这样的点,那么必然是环路
        {
            cout<<"Ordering is possible."<<endl;
            continue;
        }
        else if(j==2)//如果刚好出现了两个这样的点,那么再判断这两个点是否满足起点和终点情况
        {
            if((out[p[0]]-in[p[0]]==1&&in[p[1]]-out[p[1]]==1)||
               (out[p[0]]-in[p[0]]==-1&&in[p[1]]-out[p[1]]==-1))
            {
                cout<<"Ordering is possible."<<endl;
                continue;
            }
        }
        cout<<"The door cannot be opened."<<endl;//其他情况
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值