题意:
这个英语游戏是一个简单的英语单词连接游戏。
规则如下:一本词典中有N个英语单词,每个单词都有自己的权重v。如果使用相应的词,则有一个权重。现在有一个目标字符串X。你必须在字典里挑选一些单词,然后把它们连接到X表中。同时,你选择的词的总权重一定是最大的。
输入
有几个测试用例。对于每个试验,首先给出N(1<=N<=1000)和X(X的长度不大于10000)。接着是N行。每行包含一个单词wi(长度不大于30)及其权重。每个单词都由小写字母组成。字典里没有两个词是相同的。
输出
对于每个测试用例,输出最大的和权重,如果不能形成字符串X,则输出-1。
题解:定义f[i]为已经选到第i个位置所能凑到的最大价值,则f[i]的所有子集及对于一个当前字符串而言后缀中所有包含单词的及集合。如果数据小的话其实到这已经可以做了,如果数据大的话需要利用字符串hash或者字典树来判断当前后缀是否是一个单词。
AC代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1010;
int n;
string s;
int son[N*30][30],idx;
int f[N*30],w[N*30];
void insert(string a,int b){
int p=0;
//cout<<a<<"****"<<endl;
for(int i=0;i<a.size();i++){
int k=a[i]-'a';
if(!son[p][k]) son[p][k]=++idx;
p=son[p][k];
}
//cout<<p<<"****"<<endl;
w[p]=b;
}
int main(){
while(cin>>n>>s){
memset(son,0,sizeof son);
idx=0;
memset(w,-1,sizeof w);
memset(f,-1,sizeof f);
while(n--){
string x;
int w;
cin>>x>>w;
reverse(x.begin(),x.end());
insert(x,w);
}
f[0]=0;
for(int i=1;i<=s.size();i++){
int p=0;
for(int j=i;j>=1&&j>=i-30;j--){
int k=s[j-1]-'a';
//cout<<s[j-1]<<"******"<<endl;
if(!son[p][k])break;
p=son[p][k];
if(w[p]!=-1&&f[j-1]!=-1){
//cout<<i<<" "<<w[p]<<endl;
f[i]=max(f[i],f[j-1]+w[p]);
}
}
}
if(f[s.size()])cout<<f[s.size()]<<endl;
else cout<<-1<<endl;
}
}