01背包问题的分析与优化

背包问题是动态规划的经典问题,可以分为多个子结构,如,

只使用第1个物品在背包容量为1的情况下背包所能装的最大价值:为V[1][1]

只使用第1个物品在背包容量为2的情况下背包所能装的最大价值:为V[1][2]

只使用第1个物品在背包容量为j的情况下背包所能装的最大价值:为V[1][j]

只使用第1,2个物品在背包容量为j的情况下背包所能装的最大价值:为V[2][j]

只使用第1,2,3...i 个物品在背包容量为j的情况下背包所能装的最大价值:为V[i][j]

当使用第 1,2,3,i-1个物品在背包剩余容量为j的情况下,在选第i个物品的时候,如果第i个物品重量大于背包容量,则第i个物品不能放进去 V[i][j] = V[i-1][j];

否则的话,就可以选择放进去或者不放进去,就要看哪种价值最大 V[i][j] = max(V[i-1][j], V[i-1][j - weight[i]] + value[i]) 

代码如下:

#define M 8 //背包容量
#define N 6	// 物品个数
#define max(x,y) x > y ? x : y	//定义比大小的宏
int V[N + 1][M + 1] = {0};	//定义一个二维数组存储所有状态的背包对应价值,因为V[0][]和V[][0]都必须初始为0所以下标0不能作为有效数据,要多设置一个下标数据
int weight[N+1] ={0,1,2,3,4,5,6};	//同上weight[]和value[]的0下标位都初始化为0,不放数据,这个不是必须的,但是方便理解
int value[N+1] = {0,2,3,4,5,6,7};
void package01()
{
	for(int i = 1; i <= N; i++)		//i对应第i个物品,i的循环放外面,这个是关键点,一行一行的写入数据。因为V[i][]对应数据是由V[i-1][]决定的,因此上一行数据的完整才能保证下一行数据完整
	{
		for(int j = 1; j <= M; j++)	//j对应当前背包能承受重量为j
		{
			if(j >= weight[i])	
			{
				V[i][j] = max(V[i - 1][j], V[i - 1][j - weight[i]] + value[i]);
			}
			else
			{
				V[i][j] = V[i - 1][j];
			}
		}
	}
}
其实数组每次写入一行数据都是根据上一行的数据进行写入,不需要用二维数组,可以用一维数组,每次根据自身进行更新即可,重点是[i-1][j - weight[i]]这个数据的意思是我要在表中上一行找比j小的数据,那换成一维的话,我找的是自身(只有一行,没有上一行)j左边的数据,这个数据必须保证是上一次(i-1)写入的,肯定不能从左向右写入数据,那样的话[i-1][j - weight[i]] 对应的就是这一次(i)写入的,上一次数据没有利用就丢失了,所以j循环应该从M到1,从右向左向一维数组写入数据。

代码如下;

void package01EX()
{
	for(int i = 1; i <= N; i++)
	{
		for (int j = M; j >= 1; j--)
		{
			if (j >= weight[i])
			{
				V[j] = max(V[j], V[j - weight[i]] + value[i]);
			}
		}
	}
}

其实刚开始还碰到一个头疼的问题,选择第i个物品,到底是放还是不放的时候,总觉得放了才好,觉得前面的选项都确定了,错就错在前面的选项并没有确定,可以亲自填一下表,就是根据那个二维数组来填表,先初始化为0,动手填了一遍就发现其实当选第i个物品的时候,前面的各个物品选择根本没有确定,二维数组已经列出了前面可选择有的可能性比如试探性的选择,放第i个物品,好那么j减去weight[i],i减去1,看看上一行数据其实是偏左方对应的那个V是多少,然后加上value[i]对应的就是放这个物品对应的价值,如果不放呢?那就直接等于它头上的那个V了,也就是V[i-1][j],就意味着不放,我的最后一步是从V[i-1][j]过渡来的,放,就是从头上偏左的那一步过渡来的,然后前面的那两步路又是从他们的前面过渡来的,一步一步填表得到的,因此放和不放对应的前面的选择是不一样的,不是一条路下来的,放了容量就减少了,往上一行找数据向左找,不放就直接头上找,左边的容积肯定比右边小,那么代价就是上一行左边的数据很有可能比右边的数据小,不可能比右边大,如果这个小点的数据加上第i个物品价值比头上的数据大,那么就意味着,放进去价值大,否则相反。也就是说我现在这一步第i个物品放与不放,就决定着上一步的容积有多少,反正容积多少的都列出来了,自己找就好了,而上一步的信息又给我提供了参考,可以分析出放与不放哪个价值大,所谓是相互关联缺一不可。



猜你喜欢

转载自blog.csdn.net/m0_37907835/article/details/78991461