UVA - 10129 Play on Words(欧拉路)

题目链接

题意:给出n个单词,问是否可以把所有单词都拍成一个序列,使得每个单词的第一个字母和上一个单词的最后一个字母相同(想象成语接龙)

分析:不难发现,除了起始单词和结束单词,每个单词均连接了两个单词(一进一出),而起始单词只有出,结束单词只有进,

把每个单词抽象为一个点,会发现这是有像图的欧拉路问题,当存在欧拉路时,存在解,有向图存在欧拉路的条件是,忽略边的方向原图连通,除起点和终点外,所有点的出入度都相等,起点 出度=入度+1,终点 出度+1=入度

代码中用并查集判断图的连通性,可以dfs写

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e5+200;
int in[30],ou[30],f[N],vis[N];
vector<int>e[30];
string s[N];
int getf(int x)
{
    return f[x]==x?x:f[x]=getf(f[x]);
}
void mix(int x,int y)
{
    int tx=getf(x),ty=getf(y);
    if(tx!=ty)
        f[tx]=ty;
}
int main()
{
    ios::sync_with_stdio(0);
    int t,n;
    cin>>t;
    while(t--)
    {
        mem(in,0);
        mem(ou,0);
        mem(vis,0);
        for(int i=0;i<26;i++)
            e[i].clear();
        cin>>n;

        for(int i=1; i<=n; i++)
        {
            f[i]=i;
            cin>>s[i];
            e[s[i][0]-'a'].push_back(i);
            int l=0,r=s[i].length()-1;
            in[s[i][l]-'a']++;
            ou[s[i][r]-'a']++;
        }
        for(int i=1;i<=n;i++)
        {
            int r=s[i][s[i].length()-1]-'a';
            for(int j=0;j<e[r].size();j++)
                mix(i,e[r][j]);
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(!vis[getf(i)])
            {
                vis[getf(i)]=1;
                ans++;
            }
        }
        int f1=0,f2=0;
        for(int i=0;i<26;i++)
        {
            if(in[i]!=ou[i])
            {
                if(in[i]==ou[i]+1&&!f2)
                    f2=1;
                else if(in[i]+1==ou[i]&&!f1)
                    f1=1;
                else
                {
                    f2=f1=-1;
                    break;
                }
            }
        }
        if(ans!=1)cout<<"The door cannot be opened."<<endl;//图不连通
        else
        {
            if(f1==1&&f2==1||f1==0&&f2==0)
            cout<<"Ordering is possible."<<endl;
            else
                cout<<"The door cannot be opened."<<endl;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值