首页 > 其他分享 >01 背包强化练习三题

01 背包强化练习三题

时间:2022-08-26 01:58:14浏览次数:83  
标签:三题 01 int maxt 背包 maxcnt include dp

## T1

题目UVA12563

思路

首先跑一遍『恰好型 01 背包』,这个在我的背包学习笔记中提到了。

memset(dp, -0x3f, sizeof(dp));
dp[0] = 0;

int n, t;
scanf("%d%d", &n, &t);
for (int i = 1; i <= n; i++)
{
	int a;
	scanf("%d", &a);
	for (int j = t; j >= a; j--) dp[j] = max(dp[j], dp[j - a] + 1);
}

输出时遵循:

  • \(dp_i\) 尽可能大。

  • 在 \(dp_i\) 最大的前提下,\(i\) 最大,这样可以多唱一会。

    不过 \(i \ne t\),因为至少要留一秒来切换成《劲歌金曲》。

  • dp 时并没有计算《劲歌金曲》,所以最后输出时,歌曲数要加 \(1\),总时间要加 \(678\)。

int maxcnt = 0, maxt = 0;
for (int i = 1; i < t; i++)
	if (dp[i] >= maxcnt)
		maxcnt = dp[i], maxt = i;
printf("Case %d: %d %d\n", num, maxcnt + 1, maxt + 678);

其他细节

  1. 关于 dp 数组的大小

应该开到 \(t\) 的大小,可 \(t \le 10^9\) 咋整?

注意到题目中的一句话:

输入保证所有 \((n+1)\) 首曲子的总长度严格大于 \(t\)。

并且:

每首歌的长度保证不超过 \(3\) 分钟。

这就说明,\(t\) 的实际最大值仅仅是 \(50 \times 180 + 678 = 9678\)。

所以 dp 数组开 \(10000\) 大小就完全足矣。

  1. \(t = 1\) 的大坑

计算结果时有这一句代码:

int maxcnt = 0, maxt = 0;

如果你没有初始化成 \(0\) 是绝对不行的。

因为当 \(t = 1\),for 循环是不会进入的,那么输出时,maxcntmaxt 的初始值将会直接影响结果。

这个应该是很明显的吧,不过我还是被坑了。

整体评价

这一题相对简单,基本是恰好背包的模板。

代码挺短的。

完整代码

#include <cstdio>
#include <iostream>
#include <cstring> //给 memset 使用。
using namespace std;
int dp[10005];
void solve(int num)
{
	memset(dp, -0x3f, sizeof(dp));
	dp[0] = 0;
	
	int n, t;
	scanf("%d%d", &n, &t);
	for (int i = 1; i <= n; i++)
	{
		int a;
		scanf("%d", &a);
		for (int j = t; j >= a; j--) dp[j] = max(dp[j], dp[j - a] + 1);
	}
	
	int maxcnt = -1, maxt;
	for (int i = 1; i < t; i++)
		if (dp[i] >= maxcnt)
			maxcnt = dp[i], maxt = i;
	printf("Case %d: %d %d\n", num, maxcnt + 1, maxt + 678);
}
int main()
{
	int T;
	scanf("%d", &T);
	for (int i = 1; i <= T; i++) solve(i);
	return 0;
}

T2

题目P2340

思路

看到关键词『选择』与 『和』 就明白可以使用 01 背包。

\(dp_{i, j}\) 中,\(i\) 与正常的 01 背包相同。

\(j\) 表示 \(s_i\) 对应的计算,\(dp_{i, j}\) 表示 \(f_i\) 对应的计算。

此处应为恰好背包,随便跑一次就结束了。

但是!!!这题完全没有这么简单!!!

细节

  1. 数组大小爆炸

dp 数组第一维:\(n\),即 \(400\)。

第二维:\(\sum_{n}^{i=1}s_i\) 对应的上下界:\(400000 + 400000 = 800000\)。

\(400 \times 800000\) 空间原地爆炸。

解决这一问题,只需使用滚动数组。

发现需要使用的只有 \(i\) 与 \((i-1)\) 两个维度。

所以,将 dp[405][800005] 压成 dp[2][800005]

那么,原本的状态转移方程:

dp[i][j] = max(dp[i-1][j], dp[i-1][j - s[i]] + f[i]);

压成:

dp[i%2][j] = max(dp[(i-1)%2][j], dp[(i-1)%2][j - s[i]] + f[i]);

即可。

  1. 第二维下标负数

\(s_i\) 有可能为负数,则下标可能出现负数并 RE

这个问题倒也不难解决,最小的负数为 \(-400000\),所以只需在计算时给下标加上 \(400000\) 来抵消负数即可。

不过输出时需要再减回 \(400000\)。

完整代码

#include <cstdio>
#include <iostream>
#include <cstring>
#define N 405
#define M 400000
#define MM 800000
using namespace std;
int s[N], f[N], dp[2][MM+5];
int main()
{
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) scanf("%d%d", &s[i], &f[i]);
	
	memset(dp, -0x3f, sizeof(dp));
	dp[0][M] = 0;
	for (int i = 1; i <= n; i++)
	{
		//取这个变量名仅仅是因为想不到好名字了。 
		int monkey = M - i*1000, banana = M + i*1000;
		for (int j = monkey; j <= banana; j++)
			if (0 <= j - s[i] && j - s[i] <= MM)
				dp[i%2][j] = max(dp[(i-1)%2][j], dp[(i-1)%2][j - s[i]] + f[i]);
	}
	int maxn = -1;
	for (int i = M; i <= MM; i++)  //等价于:0-400000 即 s 大于等于 0 
		if (dp[n%2][i] >= 0)  //等价于:f 大于等于 0 
			maxn = max(maxn, i + dp[n%2][i] - M); 
	printf("%d", maxn);
	return 0;
}

注意这行:

int monkey = M - i*1000, banana = M + i*1000;

这是一个细节优化,事实上

int monkey = M, banana = MM;

也是可行的。

你肯定会问:优化了有个屁用啊,就快个常数罢了。

不是的,快了不少呢,无优化(提交记录)接近 3s,优化(提交记录)只有 300ms!

这题到这里就基本琢磨透彻了。

整体评价

挺难的啊,黄题完全不合理,感觉与 T1 难度调转就合适了。

有很多细节需要考虑。

T3

题目P1156

思路

这题貌似与 01 背包的关系不太密切。

首先按 \(t_i\) 从小到大排序。

\(dp_j\) 表示高度为 \(j\) 时,奶牛的最长存活时间。

对于第 \(i\) 个物品,高度为 \(j\) 时,首先得保证 \(dp_j \ge t_i\),这样才能存活下来。

此时,有两种可能:

  • 垫高:\(dp_{j + h_i} = \max\begin{cases}dp_{j + h_i}\\dp_j \end{cases}\)

    并且,如果 \(j + h_i \ge d\),就可以直接输出当前时间并 return 0

  • 吃掉:\(dp_j = dp_j + f_i\)。

如果等到 \(n\) 个物品都扔完了,程序还没有退出,说明奶牛无法逃脱。

这时,答案即为将全部物品都吃掉的结果,即 \(dp_0\)。

细节

  1. dp 数组初始值

本题不是恰好背包,不需要初始无穷小。

但是,题目中提到:

卡门当前体内有足够持续 \(10\) 小时的能量。

所以初始化 \(dp_0 = 10\)。

  1. 计算『堆』与『吃』的顺序

你必须先计算『堆』的结果,再计算 『吃』的结果。

因为 『吃』 的部分会改变 \(dp_j\),而 『堆』 的结果也需要用到 \(dp_j\)。

所以不得不先算『堆』。

整体评价

实现并不难,状态转移方程使用了常用的分类法。

此题挺有价值的,可以仔细理解。

完整代码

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
struct Rubbish
{
	int t, f, h;
}a[105];
bool cmp(Rubbish x, Rubbish y)
{
	return x.t < y.t;
}
int dp[105];
int main()
{
	int d, n; //题目中的 G 用 n 代替。 
	scanf("%d%d", &d, &n);
	for (int i = 1; i <= n; i++) scanf("%d%d%d", &a[i].t, &a[i].f, &a[i].h);
	sort(a+1, a+n+1, cmp);
	dp[0] = 10;
	for (int i = 1; i <= n; i++)
		for (int j = d; j >= 0; j--)
			if (dp[j] >= a[i].t)
			{
				if (j + a[i].h >= d)
				{
					printf("%d", a[i].t);
					return 0;
				}
				dp[j + a[i].h] = max(dp[j + a[i].h], dp[j]);
				dp[j] += a[i].f;
			}
	printf("%d", dp[0]);
	return 0;
}

首发:2022-04-24 19:19:13

标签:三题,01,int,maxt,背包,maxcnt,include,dp
From: https://www.cnblogs.com/liangbowen/p/16622853.html

相关文章

  • 完全背包练习题
    题目:P2737思路:这题准确的说,是『布尔型完全背包』。先打一遍板子,很容易。intn;scanf("%d",&n);dp[0]=true;for(inti=1;i<=n;i++){ inta; scanf("%d......
  • 001-Redis的前世
    在正式的走入Redis的世界之前,我想和你一起探讨下Redis的前世,为什么会有Redis的出现?是什么促成Redis的诞生?1.数据的存储1.1早期文件存储在早期,数据库等概念还......
  • day3:101-A1-Kali Linux安装
    KaliLinux安装物理机什么是Kali系统KaliLinux是Linux系统的其中一版本,Kali其中自带了600余种安全工具,主要用于渗透测试、安全研究、计算机取证、逆向工程等等。......
  • 101. 对称二叉树
    101.对称二叉树给你一个二叉树的根节点root,检查它是否轴对称。 示例1:输入:root=[1,2,2,3,4,4,3]输出:true示例2:输入:root=[1,2,2,null,3,null,3]输出:fa......
  • P3963 [TJOI2013] 奖学金——主席树
    最后翻看题解才发现可以不用主席树……就当是练习好了基本思路本题要让中位数最大,如果是最小值最大我们可以用二分答案,二中位数最大可不可以呢?显然是不行的,所以我们枚举......
  • 01 Redis 三种搭建模式:主从模式-哨兵模式-高可用集群模式
    一、主从模式用域名指定主节点,当主节点宕机,改域名指向从节点缺点不知道什么时候挂掉,丢失数据,需要人工介入,运维24h待命 二、哨兵模式比主从模式,主要多了个哨兵,能自动......
  • 02379计算机网络管理复习汇总01
    第1章网络管理概论一、网络管理系统的层次结构:  二、网络管理框架的共同特点:管理功能分为了管理站(Manager)和代理(Agent)两局部;为了存储管理信息提供数据库支持,例如......
  • 01_Linux基础-部署-VMware-Xshell-Xftp-内核-安迪比尔定理
    博客......
  • [Oracle] LeetCode 1010 Pairs of Songs With Total Durations Divisible by 60
    Youaregivenalistofsongswheretheithsonghasadurationoftime[i]seconds.Returnthenumberofpairsofsongsforwhichtheirtotaldurationinsecon......
  • 洛谷P1001 A+B problem最全算法
    为防止大家说我误导新人,先放一个最不正常的代码。#include<iostream>usingnamespacestd;intmain(){inta,b;cin>>a>>b;cout<<a+b;ret......