背包问题真的是学一遍忘一遍,所以这次打算记录一下思考历程,以便以后查看方便
0. 01背包
问题描述:有n个重量和价值分别为 wi,vi的物品。从这些物品中挑选出总重量不超过 V 的物品, 求所有挑选方案中价值总和的最大值。
基本思路:这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。状态转移方程:
f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])
先说二维数组的方法:
不知道怎么说,直接上代码,然后详解代码意义8
思路都在注释里
//这个数组表示横行表示的是物品的体积,纵行表示的是第几个物品
//数组里的值为在包的体积为j,第i件物品的时候,所能得到的最大价值
int arr[100][100];
int w[100],c[100];//w数组是物品的价值(weight),c数组是物品的体积(cost)
int main()
{
int n,v;//物品的个数和背包的体积
scanf("%d %d",&n,&v);
for(int i=1;i<n+1;i++)
{
scanf("%d %d",&w[i],&c[i]);//输入物品的价值和消耗
}
for(int i=1;i<n+1;i++)
{
for(int j=1;j<v;j++)
{
if(c[i]>j)
{
//当物品i的体积大于当前背包体积的时候,直接继承上一件物品最优状态
//因为装不进去,arr数组每一个单位都是当前背包体积,当前见到的物品个数的情况下最优的
//所以可以保持最优状态
arr[i][j]=arr[i-1][j];
}
else
{
/* 当物品i的体积小于当前背包体积即能装进去的时候
让不装此物品的价值和装了此物品的价值做比较,选择较大值作为该状态
arr[i-1][j]为不装此物品的价值
arr[i-1][j-c[i]]+w[i]为装此物品的价值,即上一行刚好空出c[i]体积大小
物品时的最优状态,加上物品i的价值即为装i物品时的价值,然后比较这两者大小
判断该体积下是否要装物品i */
arr[i][j]=max(arr[i-1][j],arr[i-1][j-c[i]]+w[i]);
}
}
}
//这样一个循环下来,arr[n][v]即为当书包的体积为v的情况下,n个物品所能带走的最大价值
}
二维数组的方法就是太浪费空间了,其实可以用滚动数组来实现该问题,这样可以大大减少空间的使用,因为在二维数组实际上可以发现有很多数据就是承接的上一行的,其实根本没有必要这样写,完全可以用一个一维数组来减少空间复杂度
下边贴一维数组解决方法,不贴注释了,理解二维数组一维数组也就不难理解了
我把滚动数组的每一次外循环后的值写了出来(神tm,我忘了printf大法了,自己手算花了一个变化图,嘤嘤嘤),如图:
一维数组01背包:
//这个数组表示横行表示的是物品的体积,纵行表示的是第几个物品
//数组里的值为在包的体积为j,第i件物品的时候,所能得到的最大价值
int arr[100];
int w[100],c[100];//w数组是物品的价值(weight),c数组是物品的体积(cost)
int main()
{
int n,v;//物品的个数和背包的体积
scanf("%d %d",&n,&v);
for(int i=1;i<n+1;i++)
{
scanf("%d %d",&w[i],&c[i]);//输入物品的价值和消耗
}
for(int i=1;i<n+1;i++)
{
for(int j=v;j>=c[i];j--)
{
arr[j]=max(arr[j],arr[j-c[i]]+w[i]);
}
}
//这样一个循环下来,arr[v]即为当书包的体积为v的情况下,n个物品所能带走的最大价值
}
先更到这里,饿了回家恰饭了,剩下的下午更