題目連接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; }