动态规划-01背包

1.动态规划算法与分治法算法的区别:

点击这里哦!

dp经典题目:01背包
视频讲解:讲解视频(要开通活动中的基础算法题才能看)
文字讲解:这个讲的挺清楚传送门

下面的是原本的式子,没有优化,只有70分。
k(i,j) = KS(i-1,j-wi) + vi,K(i,j) = KS(i-1,j)

#include<bits/stdc++.h>
using namespace std;
const int N = 10000; 
int v[N]; // 第 i 个物品的容量大小 
int w[N]; // 第 i 个物品的价值大小 
int f[N][N]; // f[i][j]: 总体积小于 j 下 在前 i 个物品可供挑选时的集合

int main()
{
	int n, m;
	cin >> n >> m; // n-物品的个数  m-背包容量大小
	
	for(int i=1; i<=n; i++) cin >> v[i] >> w[i]; 
	
	for(int i=1; i<=n; i++) // 第 i 个物品 
		for(int j=0; j<=m; j++) // 容量大小的遍历 
			if(j >= v[i]) f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i]); //拿得下可以拿
			else f[i][j] = f[i-1][j]; // 拿不下
	
	cout << f[n][m];
	return 0;
} 

要优化空间,因为二维的会爆空间。
下面是优化过的满分

#include<bits/stdc++.h>
using namespace std;
const int N = 10000; 
int v[N]; // 第 i 个物品的容量大小 
int w[N]; // 第 i 个物品的价值大小 
int f[N]; // f[i][j]: 在小于等于 j 体积下 只有前 i 个物品可供挑选时的最优选择的最大价值 

int main()
{
	int n, m;
	cin >> n >> m; 
	
	for(int i=1; i<=n; i++) cin >> v[i] >> w[i]; 
	
	for(int i=1; i<=n; i++) // 第 i 个物品 
		for(int j=m; j>=v[i]; j--) // 优化后这里 
			f[j] = max(f[j], f[j-v[i]]+w[i]);
/*
第二层循环倒过来的原因:https://www.bilibili.com/video/BV1Yq4y1m7vF?from=search&seid=8030297889955864038&spm_id_from=333.337.0.0
*/	

	cout << f[m];  
	
	return 0;
} 

P1164 小A点菜

 题解思路:https://www.luogu.com.cn/blog/user31798/solution-p1164
/*
对比下 01背包的理解就能解决疑惑的问题!! 

f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i]); 
说明: 如果你先少拿第 i 个物品,j也减少一个 vi 那么这个时候的 f的值排名(二维图上的行)不变,你后面再加上当前物品的价值 w[i] 就是当前的值了 

if(j>a[i]) f[i][j] = f[i-1][j] + f[i-1][j-w[i]];
那么先少点一个菜,那么方案数的排名不变,但是后面我要加上 当前的方案数数 f[i-1][j]
*/

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int w[N];
int f[N][N]; // f[i][j] : 在小于等于 j 元钱的情况下,在前 i 道菜中选择菜的集合 (=方案数) 

int main()
{
	int n, m;	cin >> n >> m;
	
	for(int i=1; i<=n; i++) cin >> w[i];
	
	for(int i=1; i<=n; i++)
		for(int j=0; j<=m; j++)
		{
			if(j < w[i]) f[i][j] = f[i-1][j];
			if(j == w[i]) f[i][j] = f[i-1][j]+1;
			if(j > w[i]) f[i][j] = f[i-1][j-w[i]] + f[i-1][j];
			/*
				f[i-1][j-w[i]] 吃下这道菜的方案数,不难理解,自己推下。 
				但是 f[i-1][j] 的方案数 可不能丢,题目还要求呢,一起加进来! 
		    */
		}
		
	cout << f[n][m];
	return 0;
}
 

二维优化成一维后的代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int w[N];
int f[N]; // f[i][j] : 在小于等于 j 元钱的情况下,在前 i 道菜中选择菜的集合 (=方案数) 

int main()
{
	int n, m;	cin >> n >> m;
	
	for(int i=1; i<=n; i++) cin >> w[i];
	
	for(int i=1; i<=n; i++)
		for(int j=m; j>=w[i]; j--)
		{
			if(j == w[i]) f[j] = f[j]+1;
			if(j > w[i]) f[j] = f[j-w[i]] + f[j];
		}
	
	cout << f[m];
	
	return 0;
}

想法:如果写出了二维的代码,优化成一维的代码很容易,所以还得牢记住 01 背包的解题思路和如何优化成一维的方法

P1048 [NOIP2005 普及组] 采药

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int t[N], w[N];
int f[N][N]; // f[i][j] : 在小于等于 j 时间的情况下,在前 i 株草药的集合 (=总价值) 

int main()
{
	int T, N;	cin >> T >> N;
	
	for(int i=1; i<=N; i++) cin >> t[i] >> w[i];
	
	for(int i=1; i<=N; i++)
		for(int j=0; j<=T; j++) 
			if(j>=t[i]) f[i][j] = max(f[i-1][j], f[i-1][j-t[i]] + w[i]);
			else f[i][j] = f[i-1][j];
	
	cout << f[N][T];
	
	return 0;
}

二维数组转一维数组:

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int t[N], w[N];
int f[N][N]; // f[i][j] : 在小于等于 j 时间的情况下,在前 i 株草药的集合 (=总价值) 

int main()
{
	int T, N;	cin >> T >> N;
	
	for(int i=1; i<=N; i++) cin >> t[i] >> w[i];
	
	for(int i=1; i<=N; i++)
		for(int j=0; j<=T; j++) 
			if(j>=t[i]) f[i][j] = max(f[i-1][j], f[i-1][j-t[i]] + w[i]);
			else f[i][j] = f[i-1][j];
	
	cout << f[N][T];
	
	return 0;
}

动态规划,分治算法里最关键的问题其实是寻找原问题的子问题,
并写出递推表达式,
只要完成了这一步,
代码部分都是水到渠成的事情了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值