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.
");
}
}