Problem Statement
你最初有一个空字符串S。
此外,还有1,2,...,N个包,每个都包含一些字符串
第i个包包含Ai个字符串,Si1,Si2...SiAi
你将会重复几个步骤i=1,2...N:
- 选择并执行两个操作之一
- 付1元,从包i中选择一个字符串并将其添加到S的最后
- 什么都不做
给定一个字符串T,找到能使最终的S等于T的最小金额
如果无法将S等于T,则输出-1
Constraints
- T是由小写英文字母组成的字符串,长度为1~100(含100)
- N是1~100之间的整数
- Ai是1~10之间的整数
- Sij是小写英文字母组成的字符串,长度为1~10(含10)
解题思路:
从不同的组中选取一些字符串组成字符串T,且有的组可以不选。如果是暴力搜索会超时,所以用类似分组背包的方法,只不过要找的是最小金额,即所取的数量尽可能少,属性是min,dp数组指的是前i层字符串S组成1~s.len的最小子串数量。
将数组dp初始化为-1,即可满足无法将S变成T的情况。
AC代码如下:
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
string T;
int n,a;
int main()
{
cin>>T;
vector<int>dp(T.size()+10,-1),dp2;
cin>>n;
dp[0]=0;
for(int i=1;i<=n;i++){
cin>>a;
dp2 = dp;
for(int j=1;j<=a;j++){
string s;
cin>>s;
for(int k=0;k<T.size();k++){
if(dp[k]!=-1){
if(T.substr(k,s.size())==s){
if(dp2[k+s.size()]==-1||dp2[k+s.size()]>dp[k]+1){
dp2[k+s.size()]=dp[k]+1;
}
}
}
}
}
dp = dp2;
}
cout<<dp[T.size()]<<endl;
return 0;
}
易错点(WA32):
由于dp数组是一维的,所以在更新的过程中要注意区分本层的状态和上一层的状态。因此还需要一个数组dp2,用来更新新一层的状态,否则可能导致某一组加入了不止一个子串。