01背包问题

19 篇文章 0 订阅

01背包的具体的原理(推荐dd大牛的《背包九讲》)
例题:

HDU 2602
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2602
题解:
题目大意:
给你N个物品,一个容量为M的背包。并且给出你N个物品的价值,以及他们的容量,让你求出不超过背包容量的条件下最大的价值。
一道非常典型的01背包的模板题目。
没有优化空间的代码:

#include <bits/stdc++.h>
#include <algorithm>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
const int maxn = 1e3+10;
int w[maxn],v[maxn];
int dp[maxn][maxn];//最简单的01背包(没有空间的优化)

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&v[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]);
        met(dp,0);
        for(int i=1;i<=n;i++)//自己感觉这里就是在进行暴力的枚举,每次更新最优解。
            for(int j=0;j<=m;j++)
            {
                if(j>=w[i])//条件满足的情况下,就进行选择更新。
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
                else
                    dp[i][j]=dp[i-1][j];
            }
        printf("%d\n",dp[n][m]);
    }
}

已经进行空间优化的代码:

#include <bits/stdc++.h>
#include <algorithm>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
const int maxn = 1e3+10;
int w[maxn],v[maxn];
int dp[maxn];//01背包的空间的优化。

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&v[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]);
        met(dp,0);
        for(int i=1;i<=n;i++)
            for(int j=m;j>=0;j--)
            {
                if(j>=w[i])
                    dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
            }
        printf("%d\n",dp[m]);
    }
}

对于这里有一个小技巧,如果题目中要求的是恰好装满背包的话,把dp[0]=0,其他dp[i]=-inf。如果并没有具体要求的话,就将这些全部dp[i]=0。

HDU 2546
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2546
题解:
经典01背包+贪心
代码:

#include <bits/stdc++.h>
#include <algorithm>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
const int maxn = 1e3+10;
int dp[maxn];
int p[maxn];

int main()
{
    int n,m;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&p[i]);
        scanf("%d",&m);
        if(m<5)//这里的是非主流的打法,可以选择后面直接用m-5
            printf("%d\n",m);
        else//这里主要用到的是贪心的思想,将最大的价值直接用5买掉
        {
            m-=5;
            sort(p+1,p+1+n);
            met(dp,0);
            for(int i=1;i<n;i++)//这里因为前面的贪心,所以这里只需要对1到n-1就行了。
                for(int j=m;j>=p[i];j--)
                    dp[j]=max(dp[j],dp[j-p[i]]+p[i]);
            printf("%d\n",m+5-dp[m]-p[n]);//这里记得将原来贪心的那部分减去就行了。
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值