动态规划算法采用分治算法的思想,将原问题分成若干个子问题,然后分别求解各个子问题,最后将子问题的解组合起来得到原问题的解。分治算法递归地求解各个子问题,可能重复求解某些子问题。与分治算法不同的是,动态规划算法不是递归地求解各个子问题,它是从简单问题的解入手,逐步求解,直至求解出原问题。动态规划算法的高明之处在于,它不会重复求解某些重复出现的子问题,即重叠子问题。

01背包:

    有N件物品和一个容量为V的背包。第 i 件物品的费用是c[i],价值为w[i]。求解将那些物品放入背包可使价值总和最大。

基本思路:

    这是最基本的背包问题,特点是:每种物品仅有一件,可以放或者不放。

    用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程就是:

                 f[i][v]=max(f[i - 1][v] , f[i-1][v - c[i]] + w[i] )。

HDU 2602

代码:

#include<stdio.h>
int dp[1010][1010];
int max(int x,int y)
{
	if(x>=y)
		return x;
	else
		return y;
}
int main()
{
	int t,n,m,i,j;
	int value[1010],v[1010];
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;i++)
			scanf("%d",&value[i]);
		for(i=1;i<=n;i++)
			scanf("%d",&v[i]);
		for(i=0;i<m;i++)
			dp[1][i]=0;
		for(i=1;i<=n;i++)
			for(j=0;j<=m;j++)
			{
				if(j<v[i])
					dp[i][j]=dp[i-1][j];
				else
					dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+value[i]);
			}
		printf("%d\n",dp[n][m]);
	}
	return 0;
}

完全背包:

     有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值为w[i],求解将那些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路:

     这种问题非常类似于01背包问题,所不同的是每种物品有无限件。从拿取角度来看,策略并不是取或不取,而是取0件,取1件,取2件......等等很多种。

     状态转移方程为:  f[i][v]=max(f[i - 1][v],f[i][v - c[i]] + w[i]).

代码:

#include<stdio.h>
#include<string.h>
int dp[110],w[110],v[110];
int main()
{
	int n,m,i,j;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
			scanf("%d%d",&v[i],&w[i]);
		for(i=1;i<=n;i++)
			for(j=v[i];j<=m;j++)
				dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
		printf("%d\n",dp[m]);
	}
	return 0;
}


多重背包问题:

      有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

      这题目和完全背包问题很类似。基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则有状态转移方程:

f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i] | 0<=k<=n[i]}。