遗忘口令

来源:互联网 发布:淘宝仓库中的宝贝链接 编辑:程序博客网 时间:2024/04/28 07:33
题目描述
就像每个人都会遇到的问题一样,贝西忘了在cowtube 上的口令。不过,她还记着一些关于口令
的信息。首先,她确定口令由小写字母组成,长度为L。其次,这个密码是由几个单词组合而成
的。贝西一共认识N 个单词,每个单词长度都在1 到20 之间,由小写字母组成。最后,贝西还
记得口令上一些位置的字母,她会尽量提供记住的部分,如果有些位置上的字母不记得了,就用?
代替。
给定贝西记得的口令片段和她认识的单词列表,请恢复出她的口令,如果完全符合条件的口令不
止一个,输出按照字典序排在最前面的那个。
输入
第一行:两个用空格分开的整数:L 和N,1≤L≤1000,1≤N≤1000
第二行:一个L 长的字符串,代表口令P
第三行到N+2 行:第i+2 有一个字符串W_i,表示贝西认识的第i 个单词W_i
输出
第一行:一个字符串,表示符合条件的,在字典序下最靠前的口令
样例输入
15 6
a??l?ban???????
apple
cow
farmer
banana
bananas
pies
样例输出
Applebananapies
样例解释
(有两个可行的组合,一个是applebananapies,还有一个是applebananascow,前者较靠前)
数据规模
对于30% 的数据,有1 ≤ L,N≤ 30。

对于100% 的数据,有1 ≤ L,N≤ 1, 000。


把主串抽象为背包,单词抽象为物品,题目就变成,选若干个物品,正好“装满”容量为L的背包,并且使总价值最小,因为每个单词可以重复使用,所以这还是一个完全背包。

在完全背包中,设f[i]表示背包容量为i时最小的价值,状态转移方程为f[i]=min(f[i],f[i-w[j]]+v[j])。在这个问题中,f[i]就是当主串长度为i时,字典序最小的主串,w[j]表示该单词的长度,f[i-w[j]]+v[j]表示把单词串加到主串的末尾。

#include<iostream>#include<cstdio>#include<string>#include<algorithm>#define f(i,l,r) for(i=(l);i<=(r);i++)using namespace std;const int MAXN=1005;string a[MAXN],f[MAXN];int L,n;string Min(string a,string b){return a<b?a:b;}int main(){//freopen("forgot.in","r",stdin);//freopen("forgot.out","w",stdout);int i,j,k;scanf("%d%d",&L,&n);f(i,0,n){cin>>a[i];}f(i,1,L){f(j,1,n){int l=a[j].length();if(l>i||(f[i-l]==""&&i-l!=0)) continue;      //如果f[i-l]不能够填满,那就不能转移,而f[0]为边界 f(k,i-l+1,i){if(a[0][k-1]!='?'&&a[0][k-1]!=a[j][k-i+l-1])break;}if(k==i+1){if(f[i]=="") f[i]=f[i-l]+a[j];else         f[i]=Min(f[i],f[i-l]+a[j]);}}}cout<<f[L]<<endl;return 0;}