那些由浅入深的dp习题集

一、声明

        上一篇详解了dp背包问题,也就是dp原理知识的介绍,可详见CSDN

        纸上得来终觉浅,绝知此事要躬行。

        本篇就是配套的dp习题集,当然,有基础的完全可以直接练习。习题内容皆是各大oj上的题目,本篇则致力于编写一部习题集,实现由浅入深,一部到位

        分为三个阶段,对于每个习题,都会有详细讲解,持续更新。

 二、Step one        

         这里首先应该是01背包、完全背包、多重背包、分组背包几个经典问题,但是在上一篇已经有过详细讲解,所以这里不再赘述,我们直接看实战题目。

        P1077 [NOIP2012 普及组] 摆花

P1077 [NOIP2012 普及组] 摆花 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

        问题重述:容量体积m,物品1-n种,每个体积为1,每种最多取a[i]个,求方案数。

        思路:看完重述,模板题目。但是注意,观察它和多重背包的不同点在哪?要求的是方案数。既然是方案数,就是固定的,你不能说最大方案数是多少,不能像求最大价值一样,取不同的物品价值就不同。物品固定,一个容量,方案数就是死的。

        那我们用y总的方法分解:状态表示f[i][j]:容量为j前提下取前i个物品的方案数。状态计算:f[i][j] = \sum_{0}^{k}f[i-1][j-k]  想想台阶问题:可以一步走、可以两步走,走到当前台阶方案数=前一阶方案数+前两阶方案数。一样的道理:当前行的上一行,也就是看上一个物品,最低体积 [j-k],加k个当前物品得f[i][j]。最高体积[j],不用加的当前物品得f[i][j]。

        代码(二维,可优化):

#include <bits/stdc++.h>
using namespace std;
#define ll long long

int a[105];
ll f[105][105];

int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)cin>>a[i];

	for(int i=0;i<=n;i++)f[i][0]=1;//注意初始化第一行方案数为1,因为要用到第一行
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			for(int k=0;k<=a[i];k++){
				if(j>=k){
					f[i][j]=(f[i][j]+f[i-1][j-k])%1000007;//上一行k+1个f的和	
				}
			}
		//	cout<<f[i][j]<<" ";
		}
		//cout<<endl;
	}
	cout<<f[n][m]<<endl;
	
	return 0;
}

        P1216 [USACO1.5] [IOI1994]数字三角形 Number Triangles

P1216 [USACO1.5] [IOI1994]数字三角形 Number Triangles - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

        讲解:本题很简单,之所以列出是因为相对于一些与背包问题极相似的模板题来说,可以作为一个很经典的变式开场。

        状态计算f[i][j]=kn[i][j]+max(f[i-1][j],f[i-1][j-1])

         代码:

#include <bits/stdc++.h>
using namespace std;

int f[1005][1005];
int kn[1005][1005];

int main(){
	int r;
	cin>>r;
	for(int i=1;i<=r;i++)
		for(int j=1;j<=i;j++)
			cin>>kn[i][j];
	
	for(int i=1;i<=r;i++)
		for(int j=1;j<=i;j++)
			f[i][j]=kn[i][j]+max(f[i-1][j-1],f[i-1][j]);
	int ans=0;
	for(int i=1;i<=r;i++)ans=max(ans,f[r][i]);
	cout<<ans;
	
	return 0;
}

 类似题目:P1002 [NOIP2002 普及组] 过河卒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值