题目大意:
如果一个集合 P 中的元素可以通过串联,组成一个序列 S,那么我们认为序列 S 可以分解为 P 中的元素。元素不一定要全部出现(如下例中BBC就没有出现)。举个例子,序列 ABABACABAAB 可以分解为下面集合中的元素:
{A, AB, BA, CA, BBC}
序列 S 的前面 K 个字符称作 S 中长度为 K 的前缀。设计一个程序,输入一个元素集合以及一个大写字母序列 S ,设S’是序列S的最长前缀,使其可以分解为给出的集合P中的元素,求S’的长度K。
样例输入:
A AB BA CA BBC
.
ABABACABAABC
样例输出:
11
题解:
用了动态规划的思想,从后向前去找;
dp[i] 表示 从第i位开始的最长前缀的长度;
dp[i]=max(dp[i+len[j]]+len[j],dp[i])
上式看代码。<(  ̄^ ̄)(θ(θ☆( >_<
C++
/*
ID:mujinui1
LANG:C++
TASK:prefix
*/
#include<fstream>
#include<string>
#include<algorithm>
#include<cstring>
using namespace std;
ifstream fin("prefix.in");
ofstream fout("prefix.out");
string target,flag;
//target 目标序列 flag 读入的时候用到
int len_target; //target长度
int len[205],dp[200005];
string s[205]; //len[i] 是 s[i]的 长度
int t=0; //元素的个数
int main(){
memset(dp,0,sizeof(dp));
//read
while(fin>>flag){
if(flag=="."){
break;
}
else{
s[t]=flag;
len[t++]=flag.length();
}
}
fin>>target;
while(fin>>flag){
target+=flag;
}
len_target=target.length();
for(int i=len_target;i>=0;i--){
//这一步意义不大,脑子不用拐弯而已..
target[i+1]=target[i];
}
for(int i=len_target;i>=1;i--){
//t 个元素都遍历一遍
if(len_target-i+1>=len[j]){
bool test=true;
for(int k=0;k<len[j];k++){
if(target[i+k]!=s[j][k]){
test=false;
break;
}
}
//不同就不用做比较
if(test==true){
dp[i]=max(dp[i+len[j]]+len[j],dp[i]);
}
}
}
}
fout<<dp[1]<<endl;
return 0;
}