背包问题(简单DP)

背包问题(简单DP)

首先,第一次接触到背包问题,是通过一个叫背包九讲的东西。不得不说,背包九讲真的讲的很好,有兴趣的可以去看看。通过学长的讲解,感觉不是很懂背包问题,背包问题涉及到状态转移方程。进一步了解之后,发现用简单DP可以完美的解决背包问题,而且还变得简单了许多,话不多说,下面放一些我做过的背包问题和讲解。
第一个先放一个nyoj289(苹果),链接在此nyoj289(苹果)
题目描述:
ctest有n个苹果,要将它放入容量为v的背包。给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值。
输入描述:
有多组测试数据,每组测试数据第一行为2个正整数,分别代表苹果的个数n和背包的容量v,n、v同时为0时结束测试,此时不输出。接下来的n行,每行2个正整数,用空格隔开,分别代表苹果的大小c和价钱w。所有输入数字的范围大于等于0,小于等于1000。
输出描述:
对每组测试数据输出一个整数,代表能放入背包的苹果的总价值。
样例输入:
3 3
1 1
2 1
3 1
0 0
样例输出:
2
AC代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
int main()
{
    int s[1010],dp[1010],h[1010];
    int n,v,a,b;
    while(scanf("%d %d",&n,&v)&&n!=0&&v!=0)
    {
        memset(dp,0,sizeof(dp));
        memset(s,0,sizeof(s));
        for(int i=0; i<n; i++)
        {
            scanf("%d %d",&a,&b);
            s[i]=a;
            h[i]=b;
        }
        for(int i=0; i<n; i++)
        {
            for(int j=v; j>=s[i]; j--)
                dp[j]=max(dp[j],dp[j-s[i]]+h[i]);
        }
        printf("%d\n",dp[v]);
    }
    return 0;
}

下一个是钱币兑换问题。
题目描述:
在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法。请你编程序计算出共有多少种兑法。
输入描述:
每行只有一个正整数N,N小于32768。
输出描述:
对应每个输入,输出兑换方法数。
样例输入:
2934
12553
样例输出:
718831
13137761
AC代码:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
int dp[33000];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(dp,0,sizeof(dp));
        dp[0]=1;//题目特判,找0
        for(int i=1; i<=3; i++)//枚举1,2,3
        {
            for(int j=i; j<33000; j++)
            {
                dp[j]+=dp[j-i];//兑换方法每次相加
            }
        }
        printf("%d\n",dp[n]);
    }
    return 0;
}

下面放一个纯01背包问题,也可以当做模板使用。(01背包即物品只有一个要考虑的状态只有该物品放与不放罢了)
Bone Collector (骨头收集者)
问题描述:
Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?
在这里插入图片描述
输入描述:
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
输出描述:
One integer per line representing the maximum of the total value (this number will be less than 2 31).
样例输入:
1
5 10
1 2 3 4 5
5 4 3 2 1
样例输出:
14
AC代码:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
int w[1010],v[1010],dp[1010];
int main()
{
    int n,V,t;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d %d",&n, &V);
        for(int i=0; i<n; i++)
        {
            scanf("%d",&w[i]);//输入骨头i对应的值
        }
        for(int i=0; i<n; i++)
        {
            scanf("%d",&v[i]);//输入骨头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]);
            }
        }
        printf("%d\n",dp[V]);
    }
}

这里再放一个与钱币兑换问题异曲同工的题
Coin Change (硬币的改变)
问题描述:
Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to make
changes with these coins for a given amount of money.
For example, if we have 11 cents, then we can make changes with one 10-cent coin and one 1-cent
coin, two 5-cent coins and one 1-cent coin, one 5-cent coin and six 1-cent coins, or eleven 1-cent coins.
So there are four ways of making changes for 11 cents with the above coins. Note that we count that
there is one way of making change for zero cent.
Write a program to find the total number of different ways of making changes for any amount of
money in cents. Your program should be able to handle up to 7489 cents.
输入描述:
The input file contains any number of lines, each one consisting of a number for the amount of money
in cents.
输出描述:
For each input line, output a line containing the number of different ways of making changes with the
above 5 types of coins.
样例输入:
11
26
样例输出:
4
13
AC代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
using namespace std;
int dp[8000];
int w[5]= {1,5,10,25,50};
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(dp,0,sizeof(dp));
        dp[0]=1;//题目特判,找0
        for(int i=0; i<5; i++)//枚举1,2,3,4,5
        {
            for(int j=w[i]; j<=n; ++j)
            {
                dp[j]+=dp[j-w[i]];//次数相加
            }
        }
        printf("%d\n",dp[n]);
    }
    return 0;
}

这里再放一个完全背包的模板
湫湫系列故事——减肥记I
问题描述:
 对于吃货来说,过年最幸福的事就是吃了,没有之一!
  但是对于女生来说,卡路里(热量)是天敌啊!
  资深美女湫湫深谙“胖来如山倒,胖去如抽丝”的道理,所以她希望你能帮忙制定一个食谱,能使她吃得开心的同时,不会制造太多的天敌。

当然,为了方便你制作食谱,湫湫给了你每日食物清单,上面描述了当天她想吃的每种食物能带给她的幸福程度,以及会增加的卡路里量。
  输入描述:
   输入包含多组测试用例。
  每组数据以一个整数n开始,表示每天的食物清单有n种食物。
  接下来n行,每行两个整数a和b,其中a表示这种食物可以带给湫湫的幸福值(数值越大,越幸福),b表示湫湫吃这种食物会吸收的卡路里量。
  最后是一个整数m,表示湫湫一天吸收的卡路里不能超过m。

[Technical Specification]
  1. 1 <= n <= 100
  2. 0 <= a,b <= 100000
  3. 1 <= m <= 100000
  输出描述:
  对每份清单,输出一个整数,即满足卡路里吸收量的同时,湫湫可获得的最大幸福值。
  样例输入:
  3
3 3
7 7
9 9
10
5
1 1
5 3
10 3
6 8
7 5
6
样例输出:
10
20
下面是AC代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
using namespace std;
int n,m,dp[100000];
struct node
{
    int f,k;
} ans[100000];
int main()
{
    while(~scanf("%d",&n))
    {
        memset(dp,0,sizeof(dp));
        for(int i=1; i<=n; i++)//输入物品信息
        {
            scanf("%d %d",&ans[i].f, &ans[i].k);
        }
        scanf("%d",&m);
        for(int i=1; i<=n; i++)//枚举物品种类
        {
            for(int j=ans[i].k; j<=m; j++)//与01背包恰好相反,完全背包正是要重复访问之前状态
            {
                dp[j]=max(dp[j],dp[j-ans[i].k]+ans[i].f);
            }
        }
        printf("%d\n",dp[m]);
    }
    return 0;
}

下面放一道多重背包的问题,所谓多重背包,就是可以转化成01背包或者完全背包的一种背包问题。
悼念512汶川大地震遇难同胞——珍惜现在,感恩生活
问题描述:
急!灾区的食物依然短缺!
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?

后记:
人生是一个充满了变数的生命过程,天灾、人祸、病痛是我们生命历程中不可预知的威胁。
月有阴晴圆缺,人有旦夕祸福,未来对于我们而言是一个未知数。那么,我们要做的就应该是珍惜现在,感恩生活——
感谢父母,他们给予我们生命,抚养我们成人;
感谢老师,他们授给我们知识,教我们做人
感谢朋友,他们让我们感受到世界的温暖;
感谢对手,他们令我们不断进取、努力。
同样,我们也要感谢痛苦与艰辛带给我们的财富~
在这里插入图片描述
输入描述:
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
输出描述:
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
样例输入:
1
8 2
2 100 4
4 100 2
样例输出:
400
下面是AC代码:

#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <string.h>
#include <iostream>
using namespace std;
int v[110],w[110],c[110],dp[10010];
int main()
{
    int t,n,m,i,j,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&m, &n);
        memset(dp,0,sizeof(dp));
        for(i=1; i<=n; i++)
            scanf("%d %d %d",&v[i], &w[i], &c[i]);
        for(i=1; i<=n; i++)
            for(j=1; j<=c[i]; j++)
                for(k=m; k>=v[i]; k--)
                    dp[k]=max(dp[k],dp[k-v[i]]+w[i]);
        printf("%d\n",dp[m]);
    }
    return 0;
}

以上呢,就是几种背包的基本模板的类型题,希望对大家有所帮助。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值