题目链接
(这个题目第一眼看过去感觉和图好像关系不大,以为是一个dfs,后来菜才明白这边是用了欧拉通路的判定用做dfs的剪枝,最后的点不会 TLE。
#include<bits/stdc++.h>
using namespace std;
const int NN=1005;
struct DATA//cin和cout用怕了 还是char字符串叭……虽然这个题目好像用string没关系的 这边储存这个字符串和这个字符串的长度
{
char s[25];
int len;
};
int n;//表示字符串的个数
vector<DATA>linki;//表示字符串集合的数组
vector<int>G[NN];//用vector存图
int t1[30];//表示一个字母在字符串头出现的次数
int t2[30];//表示一个字母在字符串尾巴出现的次数
bool vis[NN];
bool ans;
int Q[NN];//储存dfs结果
bool cmp(DATA aa,DATA bb)
{
if(strcmp(aa.s,bb.s)>0)return 0;
else return 1;
}
void dfs(int k,int cnt)
{
//cout<<"!!dfs:"<<linki[k].s<<endl;
Q[cnt]=k;
//printf("Q[%d]:%d\n",cnt,k);
vis[k]=1;
if(cnt==n-1)//如果cnt到了n-1 说明字符串已经搜索到第n个了,也就是有满足的词链出现了,直接输出叭
{
ans=1;//表示有词链
for(int i=0; i<cnt; i++)
printf("%s.",linki[Q[i]].s);
printf("%s\n",linki[Q[cnt]].s);
return;
}
for(int i=0; i<G[k].size(); i++)//G【k】里面的兄弟姐妹们是可以跟在k字符串后面的
{
int v=G[k][i];
if(vis[v]!=1)
{
dfs(v,cnt+1);
if(ans==1)return;//既然已经搜索到了那么就不搜了(反正就搜一次
vis[v]=0;
}
}
vis[k]=0;
}
int main()
{
scanf("%d",&n);
for(int i=0; i<n; i++)
{
DATA pp;
scanf("%s",pp.s);
pp.len=strlen(pp.s);
t1[pp.s[0]-'a']++;//头上的字母在头上里面的数组++
t2[pp.s[pp.len-1]-'a']++;//尾巴上的字母在尾巴的数组里面++
linki.push_back(pp);
}
sort(linki.begin(),linki.end(),cmp);
// //for(int i=0;i<n;i++){
// cout<<i<<" "<<linki[i].s<<" ";
// }
// cout<<endl;
for(int i=0; i<n; i++)//构造图
{
for(int j=i+1; j<n; j++)
{
DATA p1=linki[i];
DATA p2=linki[j];
if(p1.s[p1.len-1]==p2.s[0])
G[i].push_back(j);
if(p2.s[p2.len-1]==p1.s[0])
G[j].push_back(i);
}
}
bool pig=0;
for(int i=0; i<n; i++)
{
int L=linki[i].len;
char tmp[30];
strcpy(tmp,linki[i].s);
if(t1[tmp[0]-'a']==t2[tmp[0]-'a']+1)//!!!这边是欧拉通路的关键剪枝 也就是如果一个字符串的头部 在所有字符串中(t1,t2数组里面 在头部出现的次数比在尾巴上出现的次数多一,那么它就是我要的第一个字符串 也就是出度比入度多1(好像是这样叭)
{
pig=1;
dfs(i,0);
break;
}
}
if(pig==0)dfs(0,0);//如果是欧拉回路,则任意一个字符串都行,既然要字典序最小那么就是第一个开始搜索
if(ans==0)printf("***");
return 0;
}
这个题目感觉……词链的字典序有点迷惑,一开始觉得对字符串的排序不应该用字典序(也就是上方的cmp)纠结了好久
因为
对于这个数据来说,aac.ca.c明显比这个我这个代码输出的字典序小w……总之代码是ac了,但是数据到现在都还是有点迷惑叭