(分组背包)Toyota Programming Contest 2024#3(AtCoder Beginner Contest 344)D - String Bags

作者前言

记录菜鸟的每一个不行的瞬间

题目

忘了的话点击此处前往

解题思路

这是一道典型的分组背包问题

大概就是要往一定容积的背包内要装东西,现在有好几组,但是你只能从每一组里最多拿一个,请问你应该怎么样拿才是价值最大

但是这个题是所需花费最少,也就是拿最少次数正好拼出需要的字符串

那么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[i1]+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[i1]+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; 
}

一定别搞错了从哪里遍历到哪里,这个很重要

  • 19
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值