【NOI OJ】8783 單詞接龍
阿新 • • 發佈:2019-02-04
8783:單詞接龍
- 總時間限制:
- 1000ms
- 記憶體限制:
- 65536kB
- 描述
-
單詞接龍是一個與我們經常玩的成語接龍相類似的遊戲,現在我們已知一組單詞,且給定一個開頭的字母,要求出以這個字母開頭的最長的“龍”(每個單詞都最多在“龍”中出現兩次),在兩個單詞相連時,其重合部分合為一部分,例如beast和astonish,如果接成一條龍則變為beastonish,另外相鄰的兩部分不能存在包含關係,例如at和atide間不能相連。
-
輸入
- 輸入的第一行為一個單獨的整數n(n<=20)表示單詞數,以下n行每行有一個單詞(只含有大寫或小寫字母,長度不超過20),輸入的最後一行為一個單個字元,表示“龍”開頭的字母。你可以假定以此字母開頭的“龍”一定存在。
- 輸出
- 只需輸出以此字母開頭的最長的“龍”的長度。
- 樣例輸入
-
5 at touch cheat choose tact a
- 樣例輸出
-
23
- 提示
- 連成的“龍”為atoucheatactactouchoose
- 來源
- NOIP2000複賽 普及組 第四題
- #------------------------------------------------------------------------------#
- 此題乍一看,似乎並不是很難,但需要處理以下一些情況:
- 1.單詞不能包含。
- 2.每個單詞可以用2次。
- 3.重合部分長度需減去。
- 4.重合長度是不確定的。
- 現在談談大體思路:
-
首先此題一定用深搜。
- 其次存單詞時,從f[1]開始存,而最後一個表示開頭的字母存f[0]。
- why?我們接龍時就直接從f[0]開始便不需要處理開頭的單詞。
- 接下來處理問題:
- 1.關於包含,只需查到長度len-1即可,如果還不符合便不符合。
- 2.我們可以定義一個v陣列,判斷單詞使用次數,在使用前判斷if(v[i]<2)每使用一次變v[i]++,注意遞迴完後v[i]--。
-
然後先看4.在判斷單詞是否可以連線時,我們從i=0,迴圈到i=n,即所有單詞查完,如果單詞可用便接著迴圈,查待連線單詞,如果某一位與可連線單詞相同,便再迴圈,定義一個臨時變數t,從後一位開始,查,如果不同,直接t=0,break,出迴圈後if(t)便代表可連線,開始遞迴下一個,別忘了v[i]++。(此部分便是核心演算法)
- 關於3.在判斷可連線時,總長度L便加上兩個單詞長度,然後前面的最後盤點是否完全符合的迴圈計數變數定義在外面,L直接減去它便是接龍長度了。
- 不知道是否聽懂……
-
直接上程式碼:
-
#include<cstdio> #include<cstring> struct le//定義結構體可以更方便 { char s[22];//單詞 int len;//單詞長度 int v;//單詞訪問次數 }c[22];//單詞數量不超過20個,所以c[22]即可 int n; int maxn; void jl(int x,int len)//兩個引數分別代表待連線單詞的結構體下標和長度 { for(int i=1;i<=n;i++) if(c[i].v<2)//判斷訪問次數 for(int j=0;j<c[x].len;j++)//查待連線單詞的每一個字母 if(c[x].s[j]==c[i].s[0]) { int k=1;//將迴圈變數定義在外面,方便以後相減 int t=1;//臨時變數(其實bool就行) for(int l=j+1;l<c[x].len&&k<c[i].len;k++,l++)//l表示待連線單詞下標,k是可連線單詞下標,所以在迴圈條件中需滿足它們小於(因為不能包含,所以不能等於)單詞長度 if(c[x].s[l]!=c[i].s[k]) { t=0; break; } if(t) { c[i].v++; jl(i,len+c[i].len-k);//更新長度和下標後遞迴 c[i].v--;//完成後一定記得-- } } if(len>maxn) maxn=len;//不解釋 } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",c[i].s); c[i].len=strlen(c[i].s); } scanf("%s",c[0].s); c[0].len=strlen(c[0].s);//直接將開頭字母存在0號結構體 jl(0,c[0].len);//開頭字母當第一個單詞處理 printf("%d",maxn); }
- By WZY