【洛谷】 P1019 單詞接龍-(預處理+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
說明
(連成的“龍”為atoucheatactactouchoose)
NOIp2000提高組第三題
思路:這個題目要求出的是最長的接起來的字串的長度,那就必須要求出每一個他給出的單詞的重合數,也就是說我要用到任意兩個單詞的時候,你要先知道這兩個單詞是什麼情況,
有三類的單詞是不能用的:
1.兩個單詞之間沒有重合部分的,既不能連結的
2.用的次數超過兩次的,這個題目不是用過一次,注意看題吧。。。。
3.相互包含的,這個可以根據他重合字元的長度來判斷。
其實也就是多了一個函式預處理所有的單詞,知道單詞之間的關係後,深度搜索的想法自然就出了。。
程式碼:
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<string> using namespace std; int n; string tr[30]; int yc[30][30]; int vis[30]; int mp(int x,int y) //預處理兩個單詞之間的重合字元的數目 { bool pp=true; int ky=0; for(int k=tr[x].size()-1; k>=0; k--) { for(int kx=k; kx<tr[x].size(); kx++) { if(tr[x][kx]!=tr[y][ky++]) { pp=false; break; } } if(pp==true) { return tr[x].size()-k; } ky=0; pp=true; } return 0; } char ch; int ans=-1,an=0; //an儲存某種或許可行單詞連線方式的長度 //ans儲存總體的最大值。 void dfs(int 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) //連線方式找完判斷一下大小; { ans=max(ans,an); } 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]=mp(i,j); //預處理每兩個之間的關係 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\n",ans); return 0; }