背包问题(01 hdu——2602&&多重hdu——1114Piggy-Bank)

本文详细解析了01背包、完全背包及多重背包问题的动态规划算法实现,并提供了代码示例。针对不同类型的背包问题,介绍了其定义、状态转移方程及优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

断断续续动态规划学了五天了都要,今天一定要吧背包问题解决完去学STL

1、01背包问题:

有n件物品,每件物品的重量为W[i],价值为c[i].

现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的总价值最大

其中每种物品都只有1件

【分析】

令dp[i][v]表示前i件物品恰好装入容量为v的背包中所能获得的最大价值

考虑对第i件物品的选择策略,有两种策略:

①不放第i件物品,问题转化为前i-1件物品恰好装入容量为v的背包中所能获得的最大价值

②放第i件物品,那么问题转化为前i-1件物品恰好装入容量为v-w[i]的背包中所能获得的最大价值

即dp[i-1][v-w[i]]+c[i]

因此

dp[i][v]=max{dp[i-1][v],dp[i-1][v-w[i]]+c[i]}

状态转移方程

注意到dp[i][v]只与之前的状态dp[i-1]有关

所以可以枚举i从1到n

v从0到V

通过边界dp[0][v]=0(即前0件物品放入任何容量v的背包中都只能获得价值0)

就可以把整个dp数组递推出来

而由于dp[i][v]表示的恰好是为v的情况

所以需要枚举dp[n][v],取最大值即为结果

for(int i=1;i<=n;i++)
{
    for(int v=w[i];v<=V;v++)
    {
        dp[i][v]=max(dp[i-1][v],dp[i-1][v-w[i]]+c[i]);
    }
}

把空间复杂度减小

二维数组变为一维数组

dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
for(int i=1;i<=n;i++)
{
    for(int v=V;v>=w[i];v--)
    {
        dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
    }
}

注意逆序

二维数组顺序逆序皆可

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 100
#define maxv 1000
int w[maxn],c[maxn],dp[maxv];
int main()
{
    int n,V;
    scanf("%d%d",&n,&V);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&w[i]);
    }
    for(int i=0;i<n;i++)
    {
        scanf("%d",&c[i]);
    }
    for(int v=0;v<=V;v++)
    {
        dp[v]=0;
    }
    int maxx=0;
    for(int i=1;i<=n;i++)
    {
        for(int v=V;v>=w[i];v--)
        {
            dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
        }
    }
    for(int v=0;v<=V;v++)
    {
        if(dp[v]>maxx)
        {
            maxx=dp[v];
        }
    }
    printf("%d\n",maxx);
    return 0;
}

2、完全背包问题

【问题】

与01背包的区别就是 其中每件物品都有无穷件

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

边界:dp[0][v]=0

转成一维

dp[v]=max(dp[v],dp[v-w[i]]+c[i])

正向顺序

for(int i=1;i<=n;i++)
{
    for(int v=w[i];v<=V;v++)
    {
        dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
    }
}

01背包就是给定一个容量

然后每件物品只有一件

要怎么装才能使得价值最大

【01背包例题】

题目链接:

参考博客

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
using namespace std;
#define maxn 1010
int w[maxn],v[maxn],dp[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,V;
        scanf("%d%d",&n,&V);
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            scanf("%d",&w[i]);
        }
        for(int i=0;i<n;i++)
        {
            scanf("%d",&v[i]);
        }
        for(int i=0;i<n;i++)
        {
            for(int j=V;j>=v[i];j--)
            {
                dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
            }
        }
        int max=0;
        for(int i=1;i<=V;i++)
        {
            if(dp[i]>max)
            {
                max=dp[i];
            }
        }
        printf("%d\n",max);
    }
    return 0;
}

【多重背包例题】

题目链接:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
#define maxn 500010
int value[maxn],weight[maxn],dp[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int w1,w2;
        scanf("%d%d",&w1,&w2);
        int w=w2-w1;
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&value[i],&weight[i]);
        }
        for(int i=1;i<=w;i++)
        {
            dp[i]=maxn;
        }
        //dp[0]=0;
        for(int i=0;i<n;i++)
        {
            for(int j=weight[i];j<=w;j++)
            {
                dp[j]=min(dp[j],dp[j-weight[i]]+value[i]);
            }
        }
        if(dp[w]==maxn)
            printf("This is impossible.\n");
        else
            printf("The minimum amount of money in the piggy-bank is %d.\n",dp[w]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值