1. 程式人生 > >【USACO Open11】forgot

【USACO Open11】forgot

題目描述

發生了這麼多,貝茜已經忘記了她 cowtube 密碼。然而,她記得一些有用的資訊。首先,她記得她的密碼(記為變數 PP)長度為 L(1L1,000)L(1\le L\le 1,000) 字串,並可以被分成 一個或多個詞(不一定是唯一的),詞來自於字典中 NW(1NW1,000)NW(1\le NW\le 1,000) 個獨特的詞。 一個詞 WiW_i,被定義為一個長度 1201\dots 20 的小寫字母序列(‘a’…‘z’)。她還記得她密碼中某些字母的位置。 請看下面的例子。 貝西知道她的密碼看起來像"a??l?ban???"(’?'代表一個字母,她不記得), 她的字典裡有下面的詞: apple cow farmer banana bananas pies 貝西有兩個密碼是可能的“applebananapies”和“applebananascow”。 給你字典,貝西記得的字母,請找到她的密碼。如果有一個以上的密碼是可能的,找到字典序最前的。

演算法分析

列舉每個位置和以該位置為結尾的字串,跑揹包 DP 即可,實現時可以使用 C++ STL 庫中的 string,更方便地實現字串相加和比較字典序操作,注意轉移前要判斷前一狀態是否可行。

程式碼實現

#include <cstdio>
#include <cstring>
#include <string>
char s[1005],sin[1005];int len[1005];
std::string dic[1005],f[1005];
inline bool check(int x,int y) {
	for(int i=0;i<len[y];++i) {
if(s[x-i]!=dic[y][len[y]-1-i]&&s[x-i]!='?') return false; } return true; } int main() { int l,nw;scanf("%d%d",&l,&nw); scanf("%s",s+1); for(int i=0;i<nw;++i) { scanf("%s",sin); len[i]=strlen(sin); dic[i]=sin; } for(int i=1;i<=l;++i) { for(int j=0;j<nw;++j) { if
(i-len[j]>=0&&check(i,j)) { if(i-len[j]==0||!f[i-len[j]].empty()) if(f[i].empty()||f[i]>f[i-len[j]]+dic[j]) f[i]=f[i-len[j]]+dic[j]; } } } printf("%s\n",f[l].c_str()); return 0; }