词 链 词链 词链
题目链接:luogu 1127
题目
如果单词XX的末字母与单词YY的首字母相同,则XX与YY可以相连成X.YX.Y。(注意:XX、YY之间是英文的句号“.”)。例如,单词
d
o
g
dog
dog与单词
g
o
p
h
e
r
gopher
gopher,则
d
o
g
dog
dog与
g
o
p
h
e
gophe
gopher可以相连成
d
o
g
.
g
o
p
h
e
r
dog.gopher
dog.gopher。
另外还有一些例子:
- d o g . g o p h e r dog.gopher dog.gopher
- g o p h e r . r a t gopher.rat gopher.rat
- r a t . t i g e r rat.tiger rat.tiger
- a l o h a . a l o h a aloha.aloha aloha.aloha
- a r a c h n i d . d o g arachnid.dog arachnid.dog
连接成的词可以与其他单词相连,组成更长的词链,例如:
a
l
o
h
a
.
a
r
a
c
h
n
i
d
.
d
o
g
.
g
o
p
h
e
r
.
r
a
t
.
t
i
g
e
r
aloha.arachnid.dog.gopher.rat.tiger
aloha.arachnid.dog.gopher.rat.tiger
注意到,“.”两边的字母一定是相同的。
现在给你一些单词,请你找到字典序最小的词链,使得这些单词在词链中出现且仅出现一次。
输入
第一行是一个正整数
n
(
1
≤
n
≤
1000
)
n(1≤n≤1000)
n(1≤n≤1000),代表单词数量。
接下来共有
n
n
n行,每行是一个由
1
1
1到
20
20
20个小写字母组成的单词。
输出
只有一行,表示组成字典序最小的词链,若不存在则只输出三个星号 “ ∗ ∗ ∗ ” “∗∗∗” “∗∗∗”。
样例输入
6
aloha
arachnid
dog
gopher
rat
tiger
样例输出
aloha.arachnid.dog.gopher.rat.tiger
数据范围
对于
40
%
40\%
40%的数据,有
n
≤
10
n≤10
n≤10;
对于
100
%
100\%
100%的数据,有
n
≤
1000
n≤1000
n≤1000。
思路
这道题我们用
d
f
s
dfs
dfs来做。
我们可以先枚举找到可以与某字符串相连的字符串,并且统计下来。
然后判断这张图是可以连成一条线,还是可以连成环。如果都不可以,就直接输出
“
∗
∗
∗
”
“***”
“∗∗∗”不存在。
如果可以连成线,我们只要从线的开头的点开始
d
f
s
dfs
dfs,就能直接找到答案;而如果可以连成环,就要枚举每一个点
d
f
s
dfs
dfs,找到方法就退出。
最后我们判断是否找到了答案,找到了就输出,不然就退出。
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define rr register
using namespace std;
int n,b[1001][1001],ans[1001],l[1001],letter[27];
bool in[1001],yes;
string a[1001];
void dfs(int now)//dfs
{
if (yes) return ;//已经找到了
ans[++ans[0]]=now;//标记
in[now]=1;//标记
for (int i=1;i<=b[now][0];i++)
if (!in[b[now][i]])//没有到过
dfs(b[now][i]);//dfs
if (ans[0]==n) yes=1;//找到了
else//没找到(回溯)
{
ans[0]--;
in[now]=0;
}
in[now]=0;//回溯
}
int main()
{
scanf("%d",&n);//读入
for (rr int i=1;i<=n;i++)
cin>>a[i];//读入
sort(a+1,a+n+1);//按字典序从小到大排序
for (rr int i=1;i<=n;i++)
l[i]=a[i].size();//求出长度
for (rr int i=1;i<=n;i++)
for (rr int j=1;j<=n;j++)
if (i!=j)
if (a[i][l[i]-1]==a[j][0])
b[i][++b[i][0]]=j;//统计可以与字符串i相连的字符串
for (int i=1;i<=n;i++)//算出断开的部分数
{
letter[a[i][0]-96]++;
letter[a[i][l[i]-1]-96]--;
}
int mei=0,bhuan;
for (int i=1;i<=26;i++)
{
if (letter[i]==1) {mei++;bhuan=i;}//只断了一处(线)
if (letter[i]==2||mei==2)//断两处或以上(无解)
{
printf("***");//输出
return 0;//退出
}
}
if (mei)//只能组成一个线
{
for (int i=1;i<=n;i++)
if (a[i][0]-96==bhuan)//找到线开头的点
{
dfs(i);//dfs
break;//找到了,退出
}
}
else for (rr int i=1;i<=n;i++)//可以组成一个环
{
memset(ans,0,sizeof(ans));//初始化
dfs(i);//dfs
if (yes) break;//已经找到词链,退出
}
if (yes)
{
for (rr int i=1;i<ans[0];i++)
cout<<a[ans[i]]<<".";//输出
cout<<a[ans[ans[0]]];//输出
}
else printf("***");//不存在的输出
return 0;
}