dfs 成語接龍
阿新 • • 發佈:2018-11-26
題目描述
單詞接龍是一個與我們經常玩的成語接龍相類似的遊戲,現在我們已知一組單詞,且給定一個開頭的字母,要求出以這個字母開頭的最長的“龍”(每個單詞都最多在“龍”中出現兩次),在兩個單詞相連時,其重合部分合為一部分,例如 beastbeast和astonishastonish,如果接成一條龍則變為beastonishbeastonish,另外相鄰的兩部分不能存在包含關係,例如atat 和 atideatide 間不能相連。
輸入輸出格式
輸入格式:
輸入的第一行為一個單獨的整數nn (n \le 20n≤20)表示單詞數,以下nn 行每行有一個單詞,輸入的最後一行為一個單個字元,表示“龍”開頭的字母。你可以假定以此字母開頭的“龍”一定存在.
輸出格式:
只需輸出以此字母開頭的最長的“龍”的長度
輸入輸出樣例
輸入樣例#1: 複製
5 at touch cheat choose tact a
輸出樣例#1: 複製
23
-
兩個單詞合併時,合併部分取的是最小重疊部分(並不是要把相同的全合併)
-
相鄰的兩部分不能存在包含關係就是說如果存在包含關係,就不能標記為使用過。
-
每個單詞最多出現兩次.
(其實也就是讀題問題。這些都是我所犯的錯誤,希望大家能注意一下)
好了。然後是解題思路。
首先是預處理,用yc[i][j]來儲存 第i個單詞 後連線 第j個單詞 的 最小重疊部分(mt函式)
後來預處理完了之後就是深搜:
先從第一個到最後一個單詞看一看哪個單詞是指定字母為開頭的,作為深搜的第一個單詞,同時標記使用過一次(vis[i]++)
然後繼續搜吧。
#include<cstdio> #include<iostream> #include<string> #include<cmath> using namespace std; int n;//單詞數 string tr[30];//儲存字串 int yc[30][30];//兩個字母的最小重疊部分 int vis[30];//判斷單詞使用頻率. int mt(int x, int y){//mt函式,返回x單詞後連線一個y單詞的最小重疊部分 bool pp=true; int ky=0; for(int k=tr[x].size()-1;k>=0;k--){//從x單詞尾部向前看看最小重疊部分是從哪裡開始的,以為因為是倒著來,所以保證是最小的 for(int kx=k;kx<tr[x].size();kx++){/ if(tr[x][kx]!=tr[y][ky++]){ pp=false; break; } } if(pp==true){//如果說當前以k為開頭的前一個單詞字尾 ,是後面單詞的字首,就馬上返回重疊部分。(tr[x].size()-k是找出來的規律) return tr[x].size()-k; } ky=0; pp=true;//不行就繼續 } return 0; }//可能這裡有點難理解。可以手動模擬一下 char ch;//開頭字母 int ans=-1;//答案 int an=0;//每次搜到的當前最長串 void dfs(int p){//p為尾部單詞編號(p的字尾就是“龍”的字尾,因為p已經連線到”龍“後面了) bool jx=false; for(int j=1;j<=n;j++){ if(vis[j]>=2) continue;//使用了兩次就跳過 if(yc[p][j]==0) continue;//兩單詞之間沒有重合部分就跳過 if(yc[p][j]==tr[p].size() || yc[p][j]==tr[j].size()) continue;//兩者存在包含關係就跳過 an+=tr[j].size()-yc[p][j];//兩單詞合併再減去最小重合部分 vis[j]++;//使用了一次 jx=true;//標記一下當前已經成功匹配到一個可以連線的部分 dfs(j); //接上去 an-=tr[j].size()-yc[p][j];//回溯,就要再減回去那一部分長度 vis[j]--;//回溯,使用-- } if(jx==false){//jx==false說明不能再找到任何一個單詞可以相連了 ans=max(ans,an);//更新ans } return; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) cin>>tr[i]; cin>>ch; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ yc[i][j]=mt(i,j); } }//預處理yc陣列。yc[i][j]就表示,i單詞後連線一個j單詞的最小重疊部分 //比如 i表示at,j表示att. yc[i][j]就為2 但是yc[j][i]就為0. //預處理是一個關鍵 for(int i=1;i<=n;i++){//從頭到尾看一下有沒有以指定開頭字母為開頭的單詞 if(tr[i][0]==ch){//如果有,就以當前單詞為基準進行搜尋。 vis[i]++;//使用過一次 an=tr[i].size();//更新當前串長度 dfs(i);//接上 vis[i]=0;//消除影響 } } printf("%d",ans); return 0; }