动态规划之背包01

一、概述

动态规划可能是信息学中比较棘手的一块内容了,个人认为本质和搜索比较相似。

背包问题01:有N件物品和一个容量为V的背包。第i件物品的价格(即体积,下同)是w[i],价值是c[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

如果我们定义一个二维数组dp[i][j]dp[ i ][ j ] 表示 在面对第 i 件物品,且背包容量为  j 时所能获得的最大价值 ,那么我们会发现,dp[0][j]dp[i][0]都要确保为0
那么对于第i行怎么填写呢?不难发现对于一个物品,只有两种情况:

  情况一: 第i件不放进去,这时所得价值为:dp[i-1][v]

  情况二: 第i件放进去,这时所得价值为:dp[i-1][v-c[i]]+w[i] 

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

二、经典例(水)题讲解

提到dp这恐怕是经(超)典(水)的一道题。

洛谷 P1048采药

这种题明显就是背包问题的模板化用,请大家结合上面内容自行理解。

代码如下:

#include<algorithm>
#include <iostream>
#include<cstdio>
using namespace std;
int w[105],val[105];
int dp[105][1005];
int t,m;
int main()
{
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&w[i],&val[i]);
    }
    for(int i=1;i<=m;i++) //从第一件开始枚举 
        for (int j=t;j>=0;--j)//背包容量 
        {
            if(j>=w[i])
            {
                dp[i][j]=max(dp[i-1][j-w[i]]+val[i],dp[i-1][j]);
            }  
            else
            {
                dp[i][j]=dp[i-1][j];
            }              
        }
    printf("%d",dp[m][t]);
    return 0;
}

当然,不可能每个题都这么直白,可能稍微有些变形,大家一定要擦亮双眼,找到其中的关键元素:

举个例子 洛谷 P1049 装箱问题(其实也很水)

这个题乍一看,只有大小没有说价值啊?

其实不难发现,我们也可以把它所占的空间视为它的价值。

代码如下:

#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
int v,n;
int w[35],val[35];
int dp[35][20000];
int main()
{
	scanf("%d%d",&v,&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&w[i]);
		val[i]=w[i];//核心重点 
	}
	
    for(int i=1;i<=n;i++) 
        for (int j=v;j>=0;--j)
        {
            if(j>=w[i])
            {
                dp[i][j]=max(dp[i-1][j-w[i]]+val[i],dp[i-1][j]);
            }  
            else
            {
                dp[i][j]=dp[i-1][j];
            }              
        }
	printf("%d",v-dp[n][v]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41754350/article/details/81783550
今日推荐