0_1 背包动态规划详解

来源:互联网 发布:深蓝软件 编辑:程序博客网 时间:2024/06/05 09:19

1. 问题描述

现在摆在你面前n件物品,已有一个旅行包,一共可以放c kg的东西。

N件物品时这样的:

重量依次是:

W1, W2, W2…….. Wn

价值:

V1, V2, V2…….. Vn

现在让你去选择这些物品,要让它价值最大,但是不能超过包的总重量。

2. 问题的数学定义

摆在面前的n件物品,你是选还是不选,可以用xi (0表示不选这件物品,1表示要选这件物品)来表示:

X1, X2, X2…….. Xn

那么纯数学定义就变成了,在

W1* X1+ W2* X2+…….. Wn* Xn <= c kg 的条件下,

求:V1* X1+ V2* X2+…….. Vn* Xn的最大值?

3. 0-1背包动态规划可行性

假设现在,你选了y1,y2,……,yn 这是一个最优的解,那么同样的道理,y2,……,yn同样是一个最优的解,这就是动态规划的精髓,如果一个问题,大问题的最优解,可以划分为小问题的最优解,那么,从小问题逐步逼向大问题,就可以求出结果。

4. 动态规划方程

自己现在才慢慢感觉,算法不是要你急于马上就把代码完美的写出来,一点一点分析问题,把模型建立起来才是最重要的,下面就来看看如何建立01背包的动态规划方程。

①先来定义一般情况下的子问题:

大问题是求1至n,现在子问题的规模是 : i,i+1,………n

将其转换为数学定义:

条件是:Wi* Xi+ Wi+1* Xi+1+…….. Wn* Xn <= j kg

目标是求:Vi* Xi+ Vi+1* Xi+1+…….. Vn* Xn 的最大值

m(ij)表示:背包容量为j,可选择物品为ii+1,…,n时0_1背包问题的最优值。 (1≤jc

②对于一般情况的动态规划方程

一、边界条件(先我们从第n件物品开始取,当然也可以从第1件开始取)

Vn (如果第n个我选了, j>= Wn)

m(n,j)=

0 (如果第n个我选不了,j< Wn)

二、一般条件

Max{m(i+1,j),m(i+1,j- Wi) + Vi } (j- Wi>=0,容量够得时候第i个物品可以放或者选择不放)

m(I,j)=

m(i+1,j) (j- Wi<=0,容量不够,那就不放)

注:有的人可能会觉得Max{m(i+1,j),m(i+1,j- Wi) + Vi },肯定是m(i+1,j- Wi) + Vi比较大,因为加了一个Vi嘛。其实这里不然,要注意m(i+1,j)与m(i+1,j- Wi)是不相等的。

另外,我们这里是从第n件物品开始选的,所以选i时,(i+1,i+1,……..n)这个子问题是有解得,而且m(i+1,j),左边的参数是+1,如果我们从第1个开始选就会是 ‘-’ 了。

5. 举例说明

举个例子来看一下,程序应该如何解决下面这个实际的问题。

n=3, c=6

(v1, v2, v3) = (1, 2, 5),

(w1,w2,w3) = (2, 3, 4)

主要是看二维表怎么存数据的:(行表示物品,列表示重量为多少的包)

  0 1 2 3 4 5 6 1               2               3 0 0 0 0 5 5 5

 

  0 1 2 3 4 5 6 1               2 0 0 0 2 5 5 5 3 0 0 0 0 5 5 5

 

  0 1 2 3 4 5 6 1 0 0 1 2 5 5 6 2 0 0 0 2 5 5 5 3 0 0 0 0 5 5 5

请对照公式走一遍。

6. 构造最优解

由于m(1,6) m(2,6)Þ放物品1,x1=1, c=c-w1 = 4

比较m(2,4)m(3,4)是否相等Þ不放物品2x2=0

由于m(3,4) ≠0 Þ放物品3, x3 = 1

即:最优解为(1,0,1

7. 代码

/************************************************************/

/*

题目:矩阵连乘问题

学号:2007110307

姓名:郭峰

完成时间:10月28日

*/

/************************************************************/

#include <stdio.h>

int max(int a,int b)

{

if(a > b)

return a;

else

return b;

}

void ZeroOneBag(int *v,int *w,int *x,int c,int n, int m[4][7])

{

int i,j;

for(j = 0; j < c; j++)

{

if (j < w[n]) //从第N件物品开始选,如果放不下

m[n][j]=0;

else //如果放的下

m[n][j]=v[n];

}

for(i = n-1; i >= 1; i--)//控制物品的循环,从i-1到第1件

{

for(j = 0; j < w[i]; j++)//当前这个物品放不下,则最优解为之前的解

m[i][j]=m[i+1][j];

for(j=w[i]; j<=c; j++) //当前这个物品能放进去,但是我可以放进去,也可以不放进去,另外如果我放进去了,

//那么将对之前的最优解有影响

m[i][j]=max(m[i+1][j], m[i+1][j-w[i]]+v[i]);

}

for(i = 1; i < n; i ++)//构造最优解

{

if(m[i][c] == m[i+1][c])

x[i] = 0;

else

{

x[i] = 1;

c = c-w[i];

}

}

x[n] = (m[n][c])?1:0;//m[n][c]大于0吗?大于0就是选了

return;

}

void main()

{

int i=0;

int w[4]={0,2,3,4};

int v[4]={0,1,2,5};

int x[4]={0};

int array[4][7]={0};

ZeroOneBag(v,w,x,6,3,array);

printf("The most values:%d/n",array[1][6]);

printf("/nWhich objects is selected?/n");

printf("X1,X2,........XN/n");

for(i = 1; i <= 3; i++)

printf("%d/t",x[i]);

printf("/n/n");

}

原创粉丝点击