01背包和dp入门

今天学了01背包,算是领略到dp的魅力了吧。。。>_<
开始还是有点难理解的,但是后面在草稿纸上画一画就懂了,花了半个多小时^^
第一种 01背包 1
题目大意:有一个背包体积为V,有N个物品,每个物品体积为Vi,取若干个物品放到背包里使背包剩余体积最小,每个物品只能放一次!!
输入:N,V,和N个整数表示每个物品体积

输出:一行,表示背包剩余的最小体积

其实就是要让背包里放的物品体积越大越好,我们建立可以定义个数组dp,大小是V+1,同时全部初始化为0,表示还没有放入物品
数组dp其实就是表示背包容量为0~V时可以装的物品体积的最优值

  • 由于每个物品只能放一次,所以我们要倒序遍历
  • 对于每一个物品,我们可以选择拿或者不拿
  • 如果不拿,就是保持当前状态,也就是dp[j];如果拿,就是dp[j-items[i]]+items[i] (这里的items数组是用来存储每个物品的体积的)
  • dp[j-items[i]]表示给新的物品items[i]腾出空间后,箱子原有的物品的体积和,那么现在要放入新的物品,则要加上这个物品的体积,也就是items[i]
    由于题目说到我们需要让背包中物品的体积之和最大,就用头文件中的max函数比较一下就行了
    于是我们得到状态方程:dp[j]=max(dp[j],dp[j-items[i]]+items[i])
    一开始确实难理解!!但自己造一个简单样例,把过程全部写出来就能理解了!!!
    现在我们可以得到一个完整的代码辣!!_
点击查看代码
#include<iostream>
#include<algorithm>
const int MAX_N=55;
const int MAX_V=1005;
int n,v;
int items[MAX_N];
int dp[MAX_V];
int main(){
	cin>>n>>v;
	for(int i=0;i<n;++i){
		cin>>items[i];
	}
	for(int i=0;i<v;++i){
		for(int j=v;j>=items[i];--j){//j>=items[i]是为了防止物品体积大于背包容量,倒序遍历是因为一个物品只能放一次
			dp[j]=max(dp[j],dp[j-items[i]]+items[i]);//dp[j]表示:如果背包容量是j,最多能装多少体积的东西
			//dp[j-物体体积]表示当箱子容量为dp[j-v]时,能装下的最大价值,这个值代表了“腾出v空间后,箱子原有物品的价值”。
		}
	}
	cout<<v-dp[v]<<endl;
	return 0;
}
补充一点:j>=items[i]是要保证我们的物品体积一定小于背包的体积dp[j] 这样就不会出现要让一个体积为3的物品放入体积为2的背包dp[2] 最后让背包的体积V去减去背包容量为V(dp[v])的值就可以得到最小剩余体积了。。。

第二种:01背包2
这个和上一种的唯一区别就是多了一个价值,每个物品有体积和价值,要求的就是让背包中物品价值最大

状态方程只有一个部分要变,就是把+items[i]改成+t[i](t数组表示每一个物品的价值)

点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX_N=55;
const int MAX_V=1005;
const int MAX_T=105;
int items[MAX_N],t[MAX_T],dp[1005];
int n,v;
int main(){
	cin>>n>>v;
	for(int i=0;i<n;++i){
		cin>>items[i]>>t[i];
	}
	for(int i=0;i<n;++i){
		for(int j=v;j>=items[i];--j){
			dp[j]=max(dp[j],dp[j-items[i]]+t[i]);
		}
	}
	cout<<dp[v]<<endl;//最多可以在背包里放多少价值的物品
	return 0;
}

第三种:完全背包
就是第二种+每个物品可以放无限次。。。
我们只需要把倒序遍历改成正序遍历即可

点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX_N=55;
const int MAX_V=1005;
const int MAX_T=1005;
int items[MAX_N],t[MAX_T],dp[MAX_V];
int n,v;
int main(){
	cin>>n>>v;
	for(int i=0;i<n;++i){
		cin>>items[i]>>t[i];
	}
	for(int i=0;i<n;++i){
		for(int j=items[i];j<=v;++j){//因为一个物品可以拿多次,所以正序遍历
			dp[j]=max(dp[j],dp[j-items[i]]+t[i]);
		}
	}
	cout<<dp[v]<<endl;
	return 0;
}

要赶紧去刷题了。。。。><
菜死了菜死了菜死了

posted @ 2025-07-11 13:28  polyoid  阅读(38)  评论(0)    收藏  举报