dog.gopher
gopher.rat
rat.tiger
aloha.aloha
arachnid.dog
根据本题给出的例子可知,'.' 两侧的字母一定相同, 但是第一个开头单词的字母可以是任意的,并且结尾的字母也可以是任意的,由样例提供的答案(题目要求字典序)
aloha.arachnid.dog.gopher.rat.tiger 可以看出 ' .' 两侧的字母出现的都是偶数个并且两两相对,但是a是特例,出现了3次,是尾部出现的次数 + 1
我们可以在任意举出一个例子 例如:
3
hell
low
wos 此时答案是 hell.low.wos
我们也可以发现 h 出现的次数 是1 个,也是尾部出现的次数 + 1
所以我们可以得到结论: 头部次数 = 它在尾部出现的次数 + 1,
那么它一定是第一个单词位置,那么我们再用 dfs 寻找 相互连接的单词 ,即可构成答案
但是有特殊情况, 就是第一个单词的头,和最后一个单词的尾,都是同样的单词,那么就都是偶数个 头/尾 了, 就没法用上面的办法找出现奇数次的单词构成第一个单词, 那么由于本题需要字典序, 所以我们不妨直接用 最小的单词,直接进行链接,因为 出现的单词头/尾, 都是 偶数,那么就可以直接去连接,如果匹配数量没有达到 n 个 ,那么就输出 *** ,即可
st 记录某单词在头部字母出现的次数 ed 记录某单词在尾部字母出现的次数
st[s[i][0]]++;
ed[s[i][s[i].size()-1]]++;
此时我们获取了单词出现的次数
se 判重,是否使用过
为了使dfs更快,我们提前将 某一个单词的尾部,可以对应那些个单词的头部的下标放入数组
即 if(i!=j&&s[i][s[i].size()-1]==s[j][0]) v[i].push_back(j);
然后遍历所有的单词,看一下哪一个单词的头部出现的次数 = 它尾部出现的次数 + 1;就证明它一定是开头的单词 然后调用 dfs(i,s[i]+'.',1);
因为v[i] 记录了它可以和谁连接,所以直接 auto i : v[x] 和里面获取的下标直接 连接即可
count==n 当连接数量达到 n ,证明成功,然后输出,退出程序
如果说没有找到 单词的头部出现的次数 = 它尾部出现的次数 + 1,那就证明出现了特殊情况,就可以按照 题目所说的,字典序,直接从 第一个排序好的单词,直接dfs
即dfs(1,s[1]+'.',1); 如果没有成功 输出 cout<<"***";
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
vector<int> v[N];
string s[N];
int st[N],ed[N];
bool se[N];
int n;
void dfs(int x,string str,int count)
{
if(count==n)
{
str[str.size()-1]=' ';
cout<<str;
exit(0);
}
for(auto i : v[x])
{
if(!se[i])
{
se[i]=true;
dfs(i,str+s[i]+'.',count+1);
se[i]=false;
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s[i];
st[s[i][0]]++;
ed[s[i][s[i].size()-1]]++;
}
sort(s+1,s+n+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i!=j&&s[i][s[i].size()-1]==s[j][0]) v[i].push_back(j);
}
for(int i=1;i<=n;i++)
{
if(st[s[i][0]] == ed[s[i][0]]+1)
{
se[i]=true;
dfs(i,s[i]+'.',1);
se[i]=false;
}
}
se[1]=true;
dfs(1,s[1]+'.',1);
se[1]=false;
cout<<"***";
return 0;
}