【上课写题】背包问题 C++代码

题目描述
农民john面临一个很可怕的事实,因为防范失措他存储的所有稻草给澳大利亚蟑螂吃光了,
他将面临没有稻草喂养奶牛的局面。在奶牛断粮之前,
john拉着他的马车到农民Don的农场中买一些稻草给奶牛过冬。

已知john的马车可以装的下C(1 <= C <=50,000)立方的稻草。
农民Don有H(1 <= H <= 5,000)捆体积不同的稻草可供购买,
每一捆稻草有它自己的体积(1 <= V_i <= C)。
面对这些稻草john认真的计算如何充分利用马车的空间购买尽量多的稻草给他的奶牛过冬。
现在给定马车的最大容积C和每一捆稻草的体积Vi,
john如何在不超过马车最大容积的情况下买到最大体积的稻草?
他不可以把一捆稻草分开来买。

输入输出格式
输入格式:
第一行两个整数,分别为C和H
第2..H+1行:每一行一个整数代表第i捆稻草的体积Vi

输出格式:
一个整数,为john能买到的稻草的体积。
输入输出样例
输入样例#1:
7 3
2
6
5
输出样例#1:
7

【解答】01背包

每个物品只能选或不选。转移代码dp[j]表示当开销为j时前i个干草能买到的体积。

ps:加了前缀和

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> v;
int dp[60000];
int sum[10000];
int main()
{
	int c,h;
	cin>>c>>h;
	for(int i=0;i<h;i++)
	{
		int x;
		cin>>x;
		v.push_back(x);
		sum[i+1]=sum[i]+x;
	}
	for(int i=0;i<v.size();i++)
	{
		int limit=max(v[i], c - (sum[v.size()] - sum[i]));
		for(int j=c;j>=limit;j--)
			dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
	}
	cout<<dp[c]<<endl;
}

P1616 疯狂的采药

题目描述

LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是 LiYuxiang,你能完成这个任务吗?

此题和原题的不同点:

1. 每种草药可以无限制地疯狂采摘。

2. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!

输入格式

输入第一行有两个整数,分别代表总共能够用来采药的时间 t 和代表山洞里的草药的数目 m。

第 2 到第 (m + 1) 行,每行两个整数,第 (i + 1) 行的整数ai​,bi​ 分别表示采摘第 i 种草药的时间和该草药的价值。

输出格式

输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

输入输出样例

输入 #1

70 3

71 100

69 1

1 2

输出 #1

140

【解答】 这题是完全背包的模板题,这题记得f开long long

f[i]表示利用t的时间可以有的最大价值

#include<bits/stdc++.h>
using namespace std;
long long f[10000002];//f[i]表示利用t的时间可以有的最大价值
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int time, n;
	cin >> time >> n;
	int t, v;
	for (int i = 1; i <= n; i++)
	{
		cin >> t >> v;
		for (int j = t; j <= time; j++)
		{
			f[j] = max(f[j], f[j - t] + v);
		}
	}
	cout << f[time];
}

P1776 宝物筛选

终于,破解了千年的难题。小 FF 找到了王室的宝物室,里面堆满了无数价值连城的宝物。

这下小 FF 可发财了,嘎嘎。但是这里的宝物实在是太多了,小 FF 的采集车似乎装不下那么多宝物。看来小 FF 只能含泪舍弃其中的一部分宝物了。

小 FF 对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小 FF 有一个最大载重为 W 的采集车,洞穴里总共有 n 种宝物,每种宝物的价值为 vi​,重量为 wi​,每种宝物有 mi​ 件。小 FF 希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。

输入格式

第一行为一个整数 n 和 W,分别表示宝物种数和采集车的最大载重。

接下来 nn 行每行三个整数 vi​,wi​,mi​。

输出格式

输出仅一个整数,表示在采集车不超载的情况下收集的宝物的最大价值。

【解答】多重背包模板题 

多重背包可以转化为01背包求解,可以把每次输入的s件物品分解为2的幂次和,
那么如果对于多重背包的若干种转换为二进制 表示时 如该种类有7个物品 则可以转化为 111表示 此时其实可以看作 3个单独的(1,2,4)即可表示 里面物品的取法和状态,这样就可以把7个物品转换为3个物品来考虑 同样的,我们还可以压缩成一维空间
这就是所谓的多重背包的二进制优化。
当然你也可以把s件一件一件的分解(s=1+1+…+1),用这种朴素的做法,数据大就容易超时,不推荐使用。

我选择 先拆分,再做正常01背包

#include<bits/stdc++.h>
using namespace std;
int we[1000000], va[1000000], f[1000000];
int main()
{
	int n, wh;
	cin >> n >> wh;
	int x,y,z;
    int cnt = 0;
	for (int i = 1; i <= n; i++)
	{
		cin >> x >> y >> z;//价值,重量,数量

        //这里是把物品的数量转化成2进制的和的表示,如10=8+2
        for (int j = 1; j <= z; j <<= 1)
        {
            va[++cnt] = j * x;
            we[cnt] = j * y;//价值,重量
            z -= j;
        }
        if (z)//如果还有余
        {
            va[++cnt] = x * z;
            we[cnt] = y * z;
        }

	}
    for (int i = 1; i <= cnt; ++i)
        for (int j = wh; j >= we[i]; --j)
            f[j] = max(f[j], f[j - we[i]] + va[i]);//正常的01背包
    cout << f[wh];
    return 0;
}

P1833 樱花

【解答】混合背包,把01背包、完全背包、多重背包拼拼凑凑

#include<bits/stdc++.h>
using namespace std;
int we[1000000], va[1000000], f[1000000];
int main()
{
	int nx, ny, ex, ey, n;
	scanf("%d:%d %d:%d %d", &nx, &ny, &ex, &ey, &n);
	int time;
    int t, c, p;
	time = (ex - nx) * 60 + (ey - ny);
	for (int i = 1; i <= n; i++)
	{
		cin >> t >> c >> p;
		if (p == 0)
		{
			for (int j = t; j <= time; j++)
			{
				f[j] = max(f[j], f[j - t] + c);
			}
		}
		else
		{
            int cnt = 0;
            //这里是把物品的数量转化成2进制的和的表示
            for (int j = 1; j <= p; j <<= 1)
            {
                va[++cnt] = j * c;
                we[cnt] = j * t;
                p -= j;
            }
            if (p)
            {
                va[++cnt] = c * p;
                we[cnt] = t * p;
            }
            for (int k = 1; k <= cnt; ++k)
                for (int j = time; j >= we[k]; --j)
                    f[j] = max(f[j], f[j - we[k]] + va[k]);//正常的01背包
		}
	}
	cout<<f[time]; 
	return 0;
}

P1757 通天之分组背包

题目描述

自 01 背包问世之后,小 A 对此深感兴趣。一天,小 A 去远游,却发现他的背包不同于 01 背包,他的物品大致可分为 k 组,每组中的物品相互冲突,现在,他想知道最大的利用价值是多少。【】

输入格式

两个数 m,n,表示一共有 n 件物品,总重量为 m。

接下来 n 行,每行 3 个数 ai​,bi​,ci​,表示物品的重量,利用价值,所属组数。

输出格式

一个数,最大的利用价值。

【思路】分组背包,类比01背包,记F[i][j]表示对前I组情况下分析,容量为j的背包所能达到的最大总价值。同样的转移方式,分组背包在面对一组内s个的物品时,共有s + 1种决策情况,分别是选第0 , 1 , 2... s 个物品(选第0个物品即不选该组内任何物品)。多重背包中每个物品有s个,也有s + 1 种决策情况,分别是选0 , 1 , 2... s个该物品,在此可以和上面的情况做一下对比区分。 

#include<bits/stdc++.h>
using namespace std;
const int N = 1001;
long long f[N];
int s[N];
long long w[N][N], v[N][N];
long long num;
int main() {
    int n, m;
    cin >> m >> n;
    for (int i = 1; i <= n; i++)
    {
        long long ww, vv, idxx;
        cin >> ww >> vv >> idxx;
        w[idxx][++s[idxx]] = ww;
        v[idxx][s[idxx]] = vv;
        num = max(idxx, num);
    }
    for (int i = 1; i <= num; i++)
    {
        for (int j = m; j >= 0; j--)
        {
            for (int k = 1; k <= s[i]; k++)
            {
                if (j >= w[i][k])
                    f[j] = max(f[j], f[j - w[i][k]] + v[i][k]);
            }
        }
    }
    cout << f[m] << endl;
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值