作者前言
记录菜鸟的每一个不行的瞬间
题目
解题思路
这是一道典型的分组背包问题
大概就是要往一定容积的背包内要装东西,现在有好几组,但是你只能从每一组里最多拿一个,请问你应该怎么样拿才是价值最大
但是这个题是所需花费最少,也就是拿最少次数正好拼出需要的字符串
那么dp状态就是到第i个字符之前字符串已经与模板字符串第i个字符之前相同,并且dp[i]为此时的最少花费
d
p
[
i
]
=
m
i
n
(
d
p
[
i
−
1
]
+
1
,
d
p
[
i
]
)
;
dp[i] = min(dp[i-1] + 1 , dp[i]);
dp[i]=min(dp[i−1]+1,dp[i]);
但是简单的这么写肯定是不对的,因为每一组只能拿一个,所以很有可能一组里就能拼出来整个字符串,这种写法就会导致原本应该每一组拿一个的情况拼不出来的结果一组拼完了(这道题如果你忽略了这个,你就会错1个测试点,非常难受)
那么怎么进行优化呢
这里提供一个比较简答且容易理解的方法
我们只需要再来一个数组,记录上一层的状态就行了,然后每次遍历一层就更新一下,假设这个状态数组是st,那么公式就是
d
p
[
i
]
=
m
i
n
(
d
p
[
i
]
,
s
t
[
i
−
1
]
+
1
)
;
dp[i] = min( dp[i] , st[i-1] + 1 );
dp[i]=min(dp[i],st[i−1]+1);
当然以上只是讲解分组背包的做法,这道题的具体实现肯定不是这样的
有了上述的理论,接下来看代码应该就能很好理解了
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
string t,s;
int dp[N],n,m;
int st[N];
int main()
{
cin >> t >> n;
memset(dp,0x3f,sizeof dp);
memset(st,0x3f,sizeof st);
for(int i=1;i<=n;i++){
cin >> m;
for(int j=0;j<m;j++){
cin >> s;
for(int h = t.size()-s.size(); h >= 0; h--){
if(t.substr(h,s.size()) == s){
if(h == 0) dp[s.size()-1] = 1;
else dp[h+s.size()-1] = min(dp[h+s.size()-1] , st[h-1] + 1);
}
}
}
memcpy(st,dp,sizeof dp);
}
cout << (dp[t.size() - 1] == 0x3f3f3f3f ? -1 : dp[t.size() - 1]) << endl;
}
一定别搞错了从哪里遍历到哪里,这个很重要