洛谷P1019(dfs+字串處理)
阿新 • • 發佈:2019-02-12
題目描述
單詞接龍是一個與我們經常玩的成語接龍相類似的遊戲,現在我們已知一組單詞,且給定一個開頭的字母,要求出以這個字母開頭的最長的“龍”(每個單詞都最多在“龍”中出現兩次),在兩個單詞相連時,其重合部分合為一部分,例如 beast和astonish,如果接成一條龍則變為beastonish,另外相鄰的兩部分不能存在包含關係,例如at 和 atide 間不能相連。
輸入輸出格式
輸入格式:輸入的第一行為一個單獨的整數n (n<=20)表示單詞數,以下n 行每行有一個單詞,輸入的最後一行為一個單個字元,表示“龍”開頭的字母。你可以假定以此字母開頭的“龍”一定存在.
輸出格式:只需輸出以此字母開頭的最長的“龍”的長度
重點:單詞重疊的部分不好操作
在搜尋的基礎上程式碼需要有所修改。
首先,題目包含的接龍要求大致有以下幾點:1.同一個單詞最多出現2次 2.相鄰的兩部分不能存在包含關係 3.在兩個單詞相連時,其重合部分合為一部分。
我們很容易就可以想到,使用一個結構體用於儲存各個單詞的資料,包括單詞本身,它的實際長度以及可供使用的剩餘次數(初始值為2).如下:
我們可以使用一個字元變數start用來儲存開頭的字母,然後即可開始搜尋,由於start當中的字元並不會被計入總長度,所以可以先通過一個迴圈,找到符合題意的單詞,然後再以這個單詞作為開頭,進行深搜。struct words { int left = 2, tail = 0; //剩餘的使用次數 單詞實際長度 char word[101]; //內容 }words[22];
cin >> start; for (int i = 0; i < wordTot; i++) if (words[i].word[0] == start) { words[i].left--; dfs(words[i].word, words[i].tail); //目前龍中最後一個單詞 長度 words[i].left++; }
由於單詞接龍中相鄰的兩部分不能存在包含關係,所以無論龍有多長,只需要考慮最後一個加入的單詞能夠和那些單詞拼接即可。在這裡,我們可以編寫一個函式juj來判斷兩個單詞之間重合部分長度的最小值。
int juj(char a[], char b[])
{
int al = strlen(a), bl = strlen(b), j;
bool flag = true;
for (int i = 1; i < al && i < bl; i++)
{
flag = true;
for (j = 0; j < i; j++)
if (a[al - i + j] != b[j]) { flag = false; break; }
if (flag)
return i;
}
return 0;
}
這個函式主要的原理是:在a,b兩個字串當中一個個地嘗試可能重合部分的長度,並把這個長度作為一個數值返回。如果這個長度已經不小於當中最短字串的長度,那麼說明這兩個字串沒有符合題意的重合部分,juj將返回0。
處理好了單詞重合部分,剩下的就是搜尋了。這部分比較簡單,直接照著深搜的虛擬碼模板進行填充相應的程式碼即可。
void dfs(char tail[], int num)
{
_max = max(_max, num); //更新最大值
int a; //兩個單詞重合部分的長度
for (int i = 0; i < wordTot; i++)
if (words[i].left > 0)
{
a = juj(tail, words[i].word);
if (a != 0) //判斷是否符合題意
{
words[i].left--;
dfs(words[i].word, num + words[i].tail - a); //下一步搜尋
words[i].left++;
}
}
}
這樣,程式就基本完成了,下面是完整的程式碼:#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int wordTot, _max = 0;
struct words
{
int left = 2, tail = 0; //剩餘的使用次數 單詞實際長度
char word[101]; //內容
}words[22];
int juj(char a[], char b[])
{
int al = strlen(a), bl = strlen(b), j;
bool flag = true;
for (int i = 1; i < al && i < bl; i++)
{
flag = true;
for (j = 0; j < i; j++)
if (a[al - i + j] != b[j]) { flag = false; break; }
if (flag)
return i;
}
return 0;
}
void dfs(char tail[], int num)
{
_max = max(_max, num); //更新最大值
int a; //兩個單詞重合部分的長度
for (int i = 0; i < wordTot; i++)
if (words[i].left > 0)
{
a = juj(tail, words[i].word);
if (a != 0) //判斷是否符合題意
{
words[i].left--;
dfs(words[i].word, num + words[i].tail - a); //下一步搜尋
words[i].left++;
}
}
}
int main()
{
char start;
cin >> wordTot;
for (int i = 0; i < wordTot; i++)
{
cin >> words[i].word;
words[i].tail = strlen(words[i].word);
}
cin >> start;
for (int i = 0; i < wordTot; i++)
if (words[i].word[0] == start)
{
words[i].left--;
dfs(words[i].word, words[i].tail); //目前龍中最後一個單詞 長度
words[i].left++;
}
cout << _max << endl;
return 0;
}