▍題目分析
1220:單詞接龍
時間限制: 1000 ms 內存限制: 65536 KB
提交數: 1827 通過數: 998
【題目描述】
單詞接龍是一個與我們經常玩的成語接龍相類似的游戲,現在我們已知一組單詞,且給定一個開頭的字母,要求出以這個字母開頭的最長的“龍”(每個單詞都最多在“龍”中出現兩次),在兩個單詞相連時,其重合部分合為一部分,例如beast和astonish,如果接成一條龍則變為beastonish,另外相鄰的兩部分不能存在包含關系,例如at和atide間不能相連。
【輸入】
輸入的第一行為一個單獨的整數n(n≤20)表示單詞數,以下n行每行有一個單詞(只含有大寫或小寫字母,長度不超過20),輸入的最后一行為一個單個字符,表示“龍”開頭的字母。你可以假定以此字母開頭的“龍”一定存在。
【輸出】
只需輸出以此字母開頭的最長的“龍”的長度。
【輸入樣例】
5 at touch cheat choose tact a
【輸出樣例】
23
確定算法:乍一看這道題,至少想不到有什么較優的方法,那么怎么辦呢?最簡單的方法:打暴力!!!可是,又該怎么打暴力呢?一看題目就頭疼,如何確定接龍的方法?這是最麻煩的事。那么此時就要用到搜索,因為搜索的本質正是將繁瑣的過程簡化。這里我們將會使用深度優先搜索求解。
▎題解方法
這道題就先想想大概接龍的方法吧:輸入→從開始的字符判斷有沒有能接到的龍→如果有字符串能接到,則接上去→再算出接龍后的長度→找到所有接龍情況中的最大值。
- 輸入:沒有什么技術含量,就不說了,不過最好要用string來存……
1 cin>>n; 2 for(int i=1;i<=n;i++) 3 cin>>str[i]; 4 cin>>str[n+1];//這里把開始的字符存在了所有字符串的后面一個,也可以換成一個變量
- 從開始字符判斷能不能接到龍: 1 dfs(str[n+1],1);//初始長度為1
- 如果有字符串能接到,就接上去:用dfs從1到n判斷這些字符串能不能接上去(只要看兩個字符串有沒有重疊部分就可以了),然后再繼續遞歸就可以了。
1 void dfs(string s,int length_now)//s是之前接好的龍,length_now是當前接龍的總長度 2 { 3 //do something 4 for(int i=1;i<=n;i++) 5 { 6 if(vis[i]>1) continue; 7 else 8 { 9 int add=check(s,str[i]);//當前字符串與原來字符串的重疊部分的大小 10 if(add!=0)//即兩個字符串有重疊部分 11 { 12 //do something 13 } 14 } 15 } 16 17 }
- 算出接龍后的長度:接龍長度當然是原來龍的長度+現在接上的長度-重合的長度,可以用紙筆驗證一下的。
但是怎么知道重合長度呢?這是一個麻煩事。當然我們是不知道重合長度的,所以呢?就先假設一個長度,再看看原先龍的尾巴能不能和這個字符串的頭對上,如果能就返回。再考慮以下幾個問題:
-
- Q:假設重合長度的范圍是多少?
A:從1到兩個字符串中長度最小的一個,否則容易發生數組越界。
-
- Q:應該按什么順序來假設重合長度?
A:從1開始不斷增大,因為重合長度越小,接出的龍就越長。
-
- Q:怎么判斷首尾是否一樣?
A:我們需要依靠一一對應關系。從0開始(因為字符串默認下標是從0開始的)到假設重合長度-1(同理)依次來判斷一個字符串的首元素和另一個字符串的尾元素是否相等。那么如果判斷首元素的字符串的每一位為b[ j ],那么判斷尾元素的字符串的每一位為a[ a.length( ) - i + j ],這可能有點難理解,但是只要多畫圖就明白了。
-
- Q:需要特判嗎?
A:需要。分兩種情況:一種是沒有重合長度,要返回0;另一種是兩個字符串中長度最小的長度為1,那樣因為循環的問題會直接返回0 。
1 inline int check(string a,string b) 2 { 3 int p=min(a.length(),b.length()); 4 for(int i=1;a.length()==1? i<=p:i<p;i++) 5 { 6 bool flag=true; 7 for(int j=0;j<i;j++) 8 { 9 if(a[a.length()-i+j]!=b[j]) 10 { 11 flag=false; 12 break; 13 } 14 } 15 if(flag==true) return i; 16 } 17 return 0; 18 }
5.算出所有接龍情況中的最長長度:只要每次遞歸時不斷比較就行了……
1 length=max(length,length_now);
▎Code speaks louder than words!
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 using namespace std; 5 int n,length=0,vis[1000]={0};string str[1000]; 6 inline int check(string a,string b) 7 { 8 int p=min(a.length(),b.length()); 9 for(int i=1;a.length()==1? i<=p:i<p;i++) 10 { 11 bool flag=true; 12 for(int j=0;j<i;j++) 13 { 14 if(a[a.length()-i+j]!=b[j]) 15 { 16 flag=false; 17 break; 18 } 19 } 20 if(flag==true) return i; 21 } 22 return 0; 23 } 24 void dfs(string s,int length_now) 25 { 26 length=max(length,length_now); 27 for(int i=1;i<=n;i++) 28 { 29 if(vis[i]>1) continue; 30 else 31 { 32 int add=check(s,str[i]); 33 if(add!=0) 34 { 35 vis[i]++; 36 dfs(str[i],length_now+str[i].length()-add); 37 vis[i]--; 38 } 39 } 40 } 41 42 } 43 int main() 44 { 45 cin>>n; 46 for(int i=1;i<=n;i++) 47 cin>>str[i]; 48 cin>>str[n+1]; 49 dfs(str[n+1],1); 50 cout<<length<<endl; 51 return 0; 52 }