题目连接node
咱们须要找出一条包含全部单词,这些单词在词链中出现且仅出现一次,且字典序最小的链。ios
假设咱们对每个单词连一条从首字母指向尾字母的有向边,假设存在这样的一条链,那么我c++
们所建成的图中便必定存在欧拉通路或者欧拉回路。spa
欧拉通路 从一点出发,能够通过图中每一条边的路径,被称做欧拉通路,无向图中欧拉code
欧拉通路存在的条件:若图中有且仅由两个点的出度不等于入度,且一点的出度=入度+1,另外一排序
点的入度=出度+1,则图中存在欧拉通路,且起点为出度较大的点,终点为入度较大的点。ci
欧拉回路:从图中任意一点出发,可通过全部边且回到起点的路径字符串
有向图欧拉回路判断条件:全部点的出度等于入读get
注意,欧拉回路和通路存在的必要条件是基图联通string
首先,为何咱们要建无向图而不是有向图?考虑到词链不可反转(假设词链ab.bc合法,那么c
b.ba不合法),因此只能建有向图
为何必定要存在欧拉回路或者通路呢?
分析题目,咱们将单词转化为边,那么所求的词链必定是一条欧拉通路
有了这个前提,这道题就很容易解决的,
咱们将找词链转化为有向图找欧拉通路
但词链的起点怎么肯定呢?
假设图中存在欧拉回路,那么从任意点出发均可以,但咱们要求字典序最小,因此必须从字典
序最小的单词的首字母出发
假设图中仅有欧拉通路,那么只有从通路起点出发才可通过全部边。
由于咱们须要求字典序最小的词链,因此选点按字典序从小开始选便可
分析到这,代码就能够写出来了
建图后先经过并查集来判是否连通,统计出度入度判断图的类型,找到起点按字典序来dfs便可
代码以下
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> using namespace std; const int maxn=1e3+10; int n; string st[maxn]; struct node{ int s,t; }e[maxn]; int cu[maxn]; int ru[maxn]; int fla[maxn]; int cnt; void add(int x,int y){ cnt++; e[cnt].s=x; e[cnt].t=y; } int f[maxn]; int find(int x){ if(f[x]!=x){ return f[x]=find(f[x]); } else return x; } int tot; bool jud(){ for(int i=1;i<=26;i++){ f[i]=i; } for(int i=1;i<=cnt;i++){ int a=e[i].s; int b=e[i].t; int fa = find(a),fb = find(b); if(fa != fb) f[fa] = fb; } int cn=0; for(int i=1;i<=26;i++){ if(fla[i]&&f[i]==i){ cn++; } } if(cn-1!=tot){ return false; } return true; } int vis[maxn]; int p; int ans[maxn]; void dfs(int now){ for(int i=1;i<=n;i++){ if(st[i][0]-'a'+1==now&&!vis[i]){ vis[i]=1; dfs(st[i][st[i].length()-1]-'a'+1); p++; ans[p]=i; } } return ; } int main(){ // freopen("a.in","r",stdin); cin>>n; for(int i=1;i<=n;i++){ cin>>st[i]; } int a,b; sort(st+1,st+1+n);//从小到大排序,目的是在dfs过程当中获得最优解 for(int i=1;i<=n;i++){ //cout<<st[i]<<endl; a=st[i][0]-'a'+1;//获得字符串的起始字符 b=st[i][st[i].length()-1]-'a'+1;//终止字符 // cout<<a<<" "<<b<<endl; add(a,b); // add(b,a) ; if(!fla[a]) fla[a]=1;//记录该字符是否出现,目的是判断联通 if(!fla[b]) fla[b]=1; cu[a]++;//出度 ru[b]++;//入度 } // cout<<jud(); if(!jud()){ cout<<"***"; return 0; } int s=0; int t=0; int to=0; for(int i=1;i<=26;i++){ if(ru[i]!=cu[i]){ to++;// if(cu[i]-ru[i]==1){ s=i; } if(ru[i]-cu[i]==1){ t=i; } } else if(abs(cu[i]-ru[i])>1){ cout<<"***"; return 0; } if(to==2&&(!s||!t)){ cout<<"***"; return 0; } } if(to==1||to>2){ cout<<"***"; return 0; } if(s!=0){ dfs(s); } else{ dfs(st[1][0]-'a'+1); } for(int i=p;i>=1;i--){ cout<<st[ans[i]]; if(i>1) cout<<'.'; } return 0; }