預處理+DFS【洛谷P1019】
阿新 • • 發佈:2018-11-10
照例先上題目連結:https://www.luogu.org/problemnew/show/P1019
一拿到題是懵的,讀了好幾遍題目才確定題意,想了半天都在想怎麼樣才能模擬把字串輸出出來。果然對於這種含有模擬的題目我還是很不拿手。
由於對這個題目毫無思路,在隊友@TDD的啟(講)發(解)下,我才勉強對這個題目有了新的認識。
這題根本就不需要把字元輸出出來啊!
下面是思路:
首先題目要求,求出最長的字串,那麼我們就需要找到每兩個單詞之間最短的重合長度(最小重疊部分),
舉個例子,abcd和dddddd,他們合併之後是abcddddddd,他們的最小重疊長度是1(我也不知道對不對,如果不對的話請給我留言,謝謝大家啦)
題目還給出了一個首字元,那麼我們就直接根據首字元進行暴力DFS,如果可以接龍,那麼就直接把合併上的長度加上去,直到所有的字元都不能合併為止。每一次DFS都要對於長度求一個max。
這就是大體思路,但是我們注意到,DFS裡面需要找很多次單詞的接龍單詞,這咋找啊!我哪知道這個單詞後面能接哪一個單詞啊!所以我們就需要對所有的字串進行【預處理】,func(i,j)表示第i個字串後面接第j個字串的最小重疊長度。這樣預處理完了之後,就可以愉快的DFS遼。
下面上程式碼:
#include <bits/stdc++.h> using namespace std; const int maxn = 30; int num[maxn][maxn]; int used[maxn]; int ans = 0; int tmp = 0; int n; void init() { memset(num,0,sizeof(num)); memset(used,0,sizeof(used)); } string str[maxn]; int func(int a,int b) { for(int i=str[a].size()-1;i>=0;i--) { int pb = 0; int j; for(j=i;j<str[a].size();j++) { if(str[a][j]==str[b][pb] && pb<str[b].size()) { pb++; } else { break; } } if(j>=str[a].size()) { return str[a].size()-i; } } return -1; } void dfs(int s) { bool found = false; for(int i=0;i<n;i++) { if(used[i]<2 && num[s][i]!=-1 && num[s][i]!=str[i].size() && num[s][i]!=str[s].size()) { found = true; tmp += str[i].size()-num[s][i]; used[i]++; dfs(i); tmp -= str[i].size()-num[s][i]; used[i]--; } } if(!found) { ans = max(ans,tmp); } } int main() { while(cin>>n) { for(int i=0;i<n;i++) { cin>>str[i]; } cin>>str[n]; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { num[i][j] = func(i,j); } } for(int i=0;i<n;i++) { if(str[i][0]==str[n][0]) { used[i]++; tmp = str[i].size(); dfs(i); used[i]--; } } cout<<ans<<endl; } return 0; }
總結:感覺這個題目不僅思路很混亂,而且程式碼實現也比較複雜。果然還是自己太蒻了!