代码如下:
#include <iostream>
using namespace std;
/* 0-1背包 版本1
* Time Complexity O(N*V)
* Space Complexity O(N*V)
* 设 V <= 200 N <= 10
* 状态转移方程:f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }
*/
int maxValue[11][201]; /* 前i个物体面对容量j的最大价值,即子问题最优解 */
int weight[11];
int value[11];
int V, N;
void main()
{
int i, j;
scanf("%d %d",&V, &N);
for(i = 0; i < N; ++i)
{
scanf("%d %d",&weight[i],&value[i]);
}
for(i = 0; i < N; ++i)
{
for(j = 0; j <= V; ++j) /* 容量为V 等号 */
{
if(i > 0)
{
maxValue[i][j] = maxValue[i-1][j];
if(j >= weight[i]) /* 等号 */
{
int tmp = maxValue[i-1][j-weight[i]] + value[i];
maxValue[i][j] = ( tmp > maxValue[i][j]) ? tmp : maxValue[i][j];
}
}else /* 数组第0行赋值 */
{
if(j >= weight[0])
maxValue[0][j] = value[0];
}
}
}
printf("%d",maxValue[N-1][V]);
/* 重定向输出结果到文件 */
freopen("C:\\dp.txt","w",stdout);
for(i = 0; i <= N; ++i)
{
for(j = 0; j <= V; ++j)
{
printf("%d ",maxValue[i][j]);
}
printf("\n");
}
}测试用例:程序输出的状态转移矩阵如下图,第一行表示第1个物体对于容量0至V时的最优解,即背包最大价值。该实现方法是0-1背包最基本的思想,追踪状态转移矩阵有助于加深理解,POJ上单纯的0-1背包题目也有不少,如3624等,可以水一下,加深理解。
========================================
#include <iostream>
using namespace std;
/* 0-1背包 版本2
* Time Complexity O(N*V)
* Space Complexity O(2*V)
* 设 V <= 200 N <= 10
* 状态转移方程:f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }
*/
int maxValue[2][201]; /* 前i个物体面对容量j的最大价值,即子问题最优解 */
int weight[11];
int value[11];
int V, N;
void main()
{
int i, j, k;
scanf("%d %d",&V, &N);
for(i = 0; i < N; ++i)
{
scanf("%d %d",&weight[i],&value[i]);
}
for(i = 0; i < N; ++i)
{
for(j = 0; j <= V; ++j) /* 容量为V 等号 */
{
if(i > 0)
{
k = i & 1; /* i%2 获得滚动数组当前索引 k */
maxValue[k][j] = maxValue[k^1][j];
if(j >= weight[i]) /* 等号 */
{
int tmp = maxValue[k^1][j-weight[i]] + value[i];
maxValue[k][j] = ( tmp > maxValue[k][j]) ? tmp : maxValue[k][j];
}
}else /* 数组第0行赋值 */
{
if(j >= weight[0])
maxValue[0][j] = value[0];
}
}
}
printf("%d",maxValue[k][V]);
/* 重定向输出结果到文件 */
freopen("C:\\dp.txt","w",stdout);
for(i = 0; i <= 1; ++i)
{
for(j = 0; j <= V; ++j)
{
printf("%d ",maxValue[i][j]);
}
printf("\n");
}
}这种空间循环滚动使用的思想很有意思,类似的,大家熟悉的斐波那契数列,f(n) = f(n-1) + f(n-2),如果要求解f(1000),是不需要申请1000个大小的数组的,使用滚动数组只需申请3个空间f[3]就可以完成任务。#include <iostream>
using namespace std;
/* 0-1背包 版本3
* Time Complexity O(N*V)
* Space Complexity O(V)
* 设 V <= 200 N <= 10
* 状态转移方程:v = V...0; f(v) = max{ f(v), f(v-c[i])+w[i] }
*/
int maxV[201]; /* 记录前i个物品中容量v时的最大价值 */
int weight[11];
int value[11];
int V, N;
void main()
{
int i, j;
scanf("%d %d",&V, &N);
for(i = 0; i < N; ++i)
{
scanf("%d %d",&weight[i],&value[i]);
}
/*
* 对于第i轮循环
* 求出了前i个物品中面对容量为v的最大价值
*/
for(i = 0; i < N; ++i)
{
/*
* 内循环实际上讲maxV[0...v]滚动覆盖前一轮的maxV[0...V]
* 可输出对照使用二维数组时的情况
* j从V至0逆序是防止有的物品放入背包多次
*/
for(j = V; j >= weight[i]; --j) /* weight > j 的物品不会影响状态f[0,weight[i-1]] */
{
int tmp = maxV[j-weight[i]]+value[i];
maxV[j] = (maxV[j] > tmp) ? maxV[j] : tmp;
}
}
printf("%d",maxV[V]);
}可以看出,使用一维数组,代码非常简练。#include <iostream>
using namespace std;
int maxV[201]; /* 记录前i个物品中容量v时的最大价值 */
int weight[11];
int value[11];
int V, N;
void main()
{
int i, j;
scanf("%d %d",&V, &N);
for(i = 0; i < N; ++i)
{
scanf("%d %d",&weight[i],&value[i]);
}
for(i = 1; i <= V; ++i) /* 初始化非法状态 */
{
maxV[i] = -100;
}
for(i = 0; i < N; ++i)
{
for(j = V; j >= weight[i]; --j)
{
int tmp = maxV[j-weight[i]]+value[i];
maxV[j] = (maxV[j] > tmp) ? maxV[j] : tmp;
}
}
}
为了加深理解,输出每轮循环的状态矩阵如下,对照每个物体的情况,就会理解为什么做那样的初始化了。
========================================
#include <iostream>
using namespace std;
/* 0-1背包 输出最优方案 2 直接根据状态数组算
* Time Complexity O(N*V)
* Space Complexity O(N*V)
* 设 V <= 200 N <= 10
* 状态转移方程:f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }
*/
int maxValue[11][201]; /* 记录子问题最优解 */
int weight[11];
int value[11];
int V, N;
void main()
{
int i, j;
scanf("%d %d",&V, &N);
for(i = 0; i < N; ++i)
{
scanf("%d %d",&weight[i],&value[i]);
}
for(i = 0; i < N; ++i)
{
for(j = 0; j <= V; ++j)
{
if(i > 0)
{
maxValue[i][j] = maxValue[i-1][j];
if(j >= weight[i])
{
int tmp = maxValue[i-1][j-weight[i]] + value[i];
maxValue[i][j] = ( tmp > maxValue[i][j]) ? tmp : maxValue[i][j];
}
}else
{
if(j >= weight[0])
maxValue[0][j] = value[0];
}
}
}
printf("%d\n",maxValue[N-1][V]);
i = N-1;
j = V;
while(i >= 0)
{
if(maxValue[i][j] == maxValue[i-1][j-weight[i]] + value[i])
{
printf("%d ",i);
j = j - weight[i];
}
--i;
}
}
原文地址:http://blog.csdn.net/txl199106/article/details/45869557