【搜索】 1220:單詞接龍題解


▍題目分析

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

   確定算法:乍一看這道題,至少想不到有什么較優的方法,那么怎么辦呢?最簡單的方法:打暴力!!!可是,又該怎么打暴力呢?一看題目就頭疼,如何確定接龍的方法?這是最麻煩的事。那么此時就要用到搜索,因為搜索的本質正是將繁瑣的過程簡化。這里我們將會使用深度優先搜索求解。

 

▎題解方法

  這道題就先想想大概接龍的方法吧:輸入→從開始的字符判斷有沒有能接到的龍→如果有字符串能接到,則接上去→再算出接龍后的長度→找到所有接龍情況中的最大值。

  1. 輸入:沒有什么技術含量,就不說了,不過最好要用string來存……
    1 cin>>n;
    2     for(int i=1;i<=n;i++)
    3      cin>>str[i];
    4      cin>>str[n+1];//這里把開始的字符存在了所有字符串的后面一個,也可以換成一個變量
  2. 從開始字符判斷能不能接到龍:                                                                                                                                                                                                                                                                                                                                                                 1 dfs(str[n+1],1);//初始長度為1 
  3. 如果有字符串能接到,就接上去:用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 }
  4.  算出接龍后的長度:接龍長度當然是原來龍的長度+現在接上的長度-重合的長度,可以用紙筆驗證一下的。

      但是怎么知道重合長度呢?這是一個麻煩事。當然我們是不知道重合長度的,所以呢?就先假設一個長度,再看看原先龍的尾巴能不能和這個字符串的頭對上,如果能就返回。再考慮以下幾個問題:

    •   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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM