动态规划之背包问题

动态规划(DP: Dynamic Programming) 是算法的设计方法之一。我们今天从背包问题出发。

背包问题:

有n个重量和价值分别为Wi,Vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。

输入

n = 4
(w,v) = {(2,3,(1,2),(3,4),(2,2))}
w = 5

输出

7

这是一个著名的问题,先用朴素方法,针对每个物品是否放入背包进行搜索看看。

int n , w;
int w[MAX_N], v[MAX_N];

int rec(int i , int j){
	int res;
	if(i==n){
		res =0;
	}else if(j < w[i]){
		res = rec(i+1,j);
	}else{
		res = max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
	}
	return res;
	
}


void solve(){
	printf("%d\n",rec(0,w));

}

只不过这种方法的搜索深度是n,每一层的搜索都需要两次分支,复杂度是2的n次幂。

我们发现很多有参数相同的调用。白白浪费了计算时间。采用记忆化的改进。

int dp[MAX_N+1][MAX_W+1];
int rec(int i , int j){
	if(dp[i][j]>=0){
		return dp[i][j];
	}
	int res;
	if(i==n){
		res =0;
	}else if(j < w[i]){
		res = rec(i+1,j);
	}else{
		res = max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
	}
	return dp[i][j] = res;
	
}


void solve(){
	memset(dp,-1,sizeof(dp));
	printf("%d\n",rec(0,w));

}


研究下这个记忆数组。记dp[i][j]为根据rec 定义从第i个物品开始挑选总重小于j时,总价值的最大值。于是有下面递推式

dp[n][j] = 0   
              
dp[i][j]
  1.   dp[i+1][j].        (j<w[i]2.  max(dp[i+1][j],dp[i+1][i-w[i]+v[i]]) (其他)

如上所述,不用写递归函数,直接利用递推公式将各项值计算出来。简单的用二重循环解决这一问题。


int dp[MAX_N+1][MAX_W+1]; //dp 数组

void solve(){
	for(int i= n-1; i>= 0; i--){
		for(int j = 0; j <=w; j++){
		
			if(j<w[i]){
				dp[i][j]  = dp[i+1][j];
			}else{
				dp[i][j] = max(dp[i+1][j],dp[i+1][j-w[i]]+v[i])
			}			
		}
		
	}
	printf("%d\n",dp[0][w]);



}

以这种方式一步步按顺序求出解的方法被称为动态规划法。

引用
[1] 挑战程序设计竞赛(第2版)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值