首先动态规划这里的规划是指在解决问题中解决问题的一系列的步骤和方法。动态规划往往都是解决最优化问题。
其次,动态规划它有三个性质:
1.最优子结构:就是问题的最优解包含了子问题的最优解。
2.无后向性:就是解决当前的状态,与之前的状态和之后的状态没有关系,你只需要考虑当前的状态。
3.重复子问题:当问题的各个子问题不是独立的,而是相关的,这就是重复子问题。如果各个子问题不是独立的,往往就需要使用动态规划来解决。
前面说了,动态规划是解决最优解问题的,因此,动态规划的递归方程往往含有一个max或者min的函数,或者不能写出显示的递归函数。
前面将的分治法和贪心法,他们在解决问题是,都是自顶向下的,儿动态规划往往子自底向上的,还有就是,我们要把每一个算出的子问题的解储存起来,当在解决接下来为问题是,如果需要之前的结果,就直接从存储总调用,不用再算一遍了。例如求解阶乘或者求解斐波那契数列。
今天我们将的例子是0-1背包问题。
问题描述:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。这里要注意,物品不能分割,物品的状态就是放或者不放。
解决思路:
背包的总容量是:10
W={}//各个物品的容量
V={}//各个物品的价值
因为我们要求出价值的最大值,但是我们背包的容量却不能放入所有的物品,因此我们就要考虑放入那些物品到背包。
第i个物品的状态就是能不能放进背包里面,因为背包的容量是有限的。如果不能放进去,则背包的里面物品的最大价值就是之前背包的最大价值,如果能放进去,我们就要考虑是将i放进去的价值大,还是不进去的价值大。这时候我们就要比较i的价值个之前放进背包中i-1个物品的价值,如果比之前的大就放入,小就不放。因此递归方程是:
C[I,w]表示背包的容量为w的时候,1~i个物品的价值最优值。
当i=0或者w=0时c[I,w]=0
当能放进去的时候进行判断:c[I,w]=max{c[i-1,w],c[i-1,w-wi]+v[i]}
当不能放进去的时候:c[I,w]=c[i-1,w].
根据递归方程代码为:编译环境:VS2010
// 动态规划.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <string.h>
#define N 100
int _tmain(int argc, _TCHAR* argv[])
{
//0-1背包
int w[]={0,2,2,6,5,4};//重量数组
int v[]={0,6,3,5,4,6};//价值数组
int n=5,weight=10;
* printf("输入数目:\n");
scanf("%d",&n);
printf("输入重量:\n");
scanf("%d",&weight);*/
int i,j;//i代表物品,j代表容量
*printf("输入物品的重量:\n");
for (i=0;i<n;i++)
{
scanf("%d",&w[i]);
}
printf("输入物品的价值:\n");
for (j=0;j<n;j++)
{
scanf("%d",&v[j]);
}*/
memset(c,0,sizeof(c));
for (i=0;i<=n;i++)
{
for (j=0;j<=weight;j++)
{
if (j==0||i==0)
{
c[i][j]=0;
}
else
{
if (w[i]>j)//error
{
c[i][j]=c[i-1][j];
}
else
{
c[i][j]=c[i-1][j]>(c[i-1][j-w[i]]+v[i])?c[i-1][j]:(c[i-1][j-w[i]]+v[i]);
}
}
}
}
for (i=0;i<=n;i++)
{
for (j=0;j<=weight;j++)
{
if (j%11==0)
{
printf("\n");
}
printf("%4d",c[i][j]);
}
}
printf("\n");
return 0;
}