单词游戏

https://loj.ac/problem/10106

题目描述

  给出(n)个单词,问能否完成所有单词的单词接龙。

思路

  如果以单词为节点,条件为边建图,我们就要在图上求是否存在一条哈密尔顿道路,这显然难以实现。我们考虑以单词为边,以字母为节点,那么题目就相当于在图上求一条欧拉道路,但我们并不知道图是否是一张连通图,非连通图显然无法找到一条欧拉路径。所以我们还要再尝试找一遍欧拉路径来判断是否连通。而找欧拉路径容易造成栈溢出,所以我们可以递归改循环。当然用并查集判连通性也可以。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=30,M=1e5+10;

int nxt[M],to[M],tot,head[N];
void add_edge(int x,int y)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
}

int read()
{
    int res=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+ch-'0';ch=getchar();}
    return res*w;
}

int st[M],top;
bool vis[M];
void euler(int s)
{
    st[++top]=s;
    while(top>=1)
    {
        int x=st[top],i=head[x];
        while(i&&vis[i])i=nxt[i];
        if(i)
        {
            st[++top]=to[i];
            head[x]=nxt[i];
            vis[i]=1;
        }
        else
            --top;
    }
}

char s[1100];
int in[30],out[30];
int main() 
{
    int t=read();
    while(t--)
    {
        memset(head,0,sizeof(head));
        memset(vis,0,sizeof(vis));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        top=0;tot=0;
        int n=read();
        for(int i=1;i<=n;i++)
        {
            scanf(" %s",s);
            int x=s[0]-'a'+1,y=s[strlen(s)-1]-'a'+1;
//            cout<<x<<' '<<y<<endl;
            in[y]++;out[x]++;
            add_edge(x,y);
        }
        bool f=1;
        int cnt1=0,cnt2=0,st=1;
        for(int i=1;i<=26;i++)
        {
            if(in[i]-out[i]==1)cnt1++;
            else if(out[i]-in[i]==1)cnt2++,st=i;
            else if(out[i]!=in[i])f=0;
            if(cnt1>1||cnt2>1)f=0;
        }
        euler(st);
        for(int i=1;i<=n;i++)
            if(!vis[i]){f=0;break ;}
        if(f)printf("Ordering is possible.
");
        else printf("The door cannot be opened.
");
    } 
}
原文地址:https://www.cnblogs.com/fangbozhen/p/11752952.html