这就是背包问题吗?芜湖~~

一、 什么是背包问题?

背包问题是动态规划中的一种,就像它的名字一样,往一个背包里放东西。一般背包问题的形式是给定背包的总容量、放进背包的每个物品的价值和所占的容量,求在不超过背包总容量的前提下,把物品放入背包所能获取的最大价值。
就好比,你发现了一座宝藏,里面很多宝物,但你只带了一个双肩包,你先看了一眼所有宝物,知道了它们的大概价值,每个宝物大概占多大空间,你也知道自己的包能放多少东西,你想让带走的宝物总价值最大,同时双肩包还能装得下(单押skr~~(滑稽))

二、怎么解背包问题!

先给出分析结论。
设物品总数为n,背包容量为m
按照动态规划的解题思路。
主问题:把n个物品放入容量为m的背包所能获得的最大价值.
子问题:把前i(i=1,2,n)个物品放入容量为j(j=0.1.2…m)的背包所能获得的最大价值.
用bag[i][j]表示将前i个物品放入容量为j的背包所获得的最大价值。
volume[i]表示第i个物品所占的容量
value[i]表示第i个物品的价值
动态转移方程:
if(j>volume[i])
bag[i][j]=max(bag[i-1][j],bag[i-1][j-volume[i]]+value[i])
else
bag[i][j]=bag[i-1][j]

现在来进行分析
首先当我们定义出bag[i][j]这个数组后,可以知道最终的答案就是bag[n][m]。
所以我们只要维护bag数组就可以了!!!
我们再细品一下这句话“将前i个物品放入容量为j的背包所获得的最大价值”。(你品,你细品)
然后我们可以这么想,装每一个物品时,都先拿一个空的背包,对于当前遍历的容量,看当前物品能不能放的下,如果放得下就放进去(这时当前背包里只有这一个物品),再看看还有没有多余的空间,如果有,我们再最大化利用这个剩余容量,利用的方法就是往前找,找放上一个物品的时候,这么多的容量能放下的最大价值的情况,把这个情况加入到当前的背包,如果放不下,哎,那我不放了,我选择放上一个物品时,这么多容量能放下的物品的情况。所以核心代码就出来了,没看懂的新萌们可以实现一遍再把数组更新过程输出一遍。

 for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
            if(time[i]<j)
                bag[i][j]=max(bag[i-1][j],bag[i-1][j-volume[i]]+value[i]);
             else
                bag[i][j]=bag[i-1][j];

三、三种背包问题

【1】 01背包

01背包的特点就是每种物品只有一件,直接莽!!这里有一个小简化,就是二维数组变一维数组,因为每次维护的时候都只用到了上一层,注意要从尾部开始更新,不然要用到的数据会先被先更新掉。

 for(int i=1; i<=n; i++)
        for(int j=m; j>0; j--)
            if(time[i]<j)
                bag[j]=max(bag[j],bag[j-volume[i]]+value[i]);

洛谷p1048:采药

题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
输入格式
第一行有 2 个整数 T(1≤T≤1000)和 M(1≤M≤100),用一个空格隔开,T 代表总共能够用来采药的时间,M 代表山洞里的草药的数目。
接下来的 M行每行包括两个在 1 到 100之间(包括 1 和 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式
输出在规定的时间内可以采到的草药的最大总价值。
输入输出样例

输入#1

70 3
71 100
69 1
1 2

输出#1

3

#include <iostream>
using namespace std;
const int MAXN=3000;
int main()
{
    int t,m;
    int bg[MAXN]={0},val[MAXN],time[MAXN];
    cin>>t>>m;
    for(int i=1; i<=m; i++)
        cin>>time[i]>>val[i];
    for(int i=1; i<=m; i++)
        for(int j=t; j>0; j--)
            if(time[i]<=j)
                bg[j]=max(bg[j],bg[j-time[i]]+val[i]);
   cout<<bg[t];

    return 0;
}

【2】多重背包

多重背包的变化就是每种物品不是一件,是有限多件,直接n个物品i分别存成n个物品再用01背包的方法解决就好了。
(暂时没找到例题,找到了再补上)

【3】完全背包

完全背包的变化就是每种物品都有无数件,这回咱们j的遍历就必须从头部开始更新了,利用的原理就是在维护每一层i时,不断的我更新我自己。

洛谷p1616:疯狂的采药

题目描述
LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是 LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
1 . 每种草药可以无限制地疯狂采摘。
2 . 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!
输入格式
输入第一行有两个整数,分别代表总共能够用来采药的时间 ttt 和代表山洞里的草药的数目 m。
第 2 到第(m+1) 行,每行两个整数,第 (i+1)行的整数 ai,bi分别表示采摘第 i 种草药的时间和该草药的价值。
输出格式
输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
输入输出样例
输入 #1

70 3
71 100
69 1
1 2

输出 #1

140

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e7+5;
long long  bg[MAXN]= {0},val[MAXN],ti[MAXN];
int main()
{
    int t,m;
    cin>>t>>m;
    for(int i=1; i<=m; i++)
        cin>>ti[i]>>val[i];
    for(int i=1; i<=m; i++)
        for(int j=ti[i]; j<=t; j++)
            bg[j]=max(bg[j],bg[j-ti[i]]+val[i]);
    cout<<bg[t];

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值