【蓝桥杯官网试题 - 算法提高 】求最大值 (dp,0-1背包)
题干:
问题描述
给n个有序整数对ai bi,你需要选择一些整数对 使得所有你选定的数的ai+bi的和最大。并且要求你选定的数对的ai之和非负,bi之和非负。
输入格式
输入的第一行为n,数对的个数
以下n行每行两个整数 ai bi
输出格式
输出你选定的数对的ai+bi之和
样例输入
5
-403 -625
-847 901
-624 -708
-293 413
886 709
样例输出
1715
数据规模和约定
1<=n<=100
-1000<=ai,bi<=1000
时间限制:1.0s 内存限制:256.0MB
解题报告:
不直接计算选定的数的ai+bi的和,而是转化为计算在ai的和一定的情况下尽量使选定的bi的和最大。于是变成为一个01背包问题,ai的值作为物体的重量,bi的值作为该物体的价值。首先过滤掉所有ai和bi均小于0的数对,令dp[i][j]表示前i个数对,选定的ai的和为j的情况下bi的和的最大值,将dp[i][j]初始化为-INF,再将所有已知合法情况初始化:dp[i][a[i]] = b[i],之后dp[i][j] = max(dp[i - 1][j], dp[i][j]),若j - a[i]存在,dp[i][j] = max(dp[i][j], dp[i - 1][j - a[i]] + b[i])。最后再统一加偏移量ZERO。值得注意的是,这个背包问题虽然也可以优化成一维,但是没必要,如果优化成一维,对于这题代码不会更简练反而会复杂不少,因为这题初始化的时候不能只对二维数组的第一行进行初始化,需要每一行都有一个值进行初始化,所以最好的办法就是直接开二维数组做最朴素的01背包,而且这题空间给的足够大,所以不需要担心MLE的问题。
AC代码:(空间大概78MB)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
int tot;
int a[101],b[101];
int dp[101][200000 + 5];//截止到第i个,a[i]和为j的情况下,b[i] 的最大值
int zero = 100000;
const int INF = 0x3f3f3f3f;
int main()
{int n;cin>>n;for(int x,y,i = 1; i<=n; i++) {scanf("%d%d",&x,&y);if(x < 0 && y < 0) continue;a[++tot] = x, b[tot] = y;} for(int i = 0; i<=tot; i++) {for(int j = -100000; j<=100000; j++) {dp[i][j+ zero] = -INF;}}for(int i = 1; i<=tot; i++) {dp[i][a[i]+ zero] = b[i];}for(int i = 2; i<=tot; i++) {for(int j = -100000; j<=100000; j++) {if(dp[i-1][j+ zero] != -INF) dp[i][j+ zero] = max(dp[i][j+zero],dp[i-1][j+ zero]);if(j - a[i] + zero >= 0 && j - a[i] + zero <= 200000) //这句必须加。 dp[i][j+ zero] = max(dp[i][j+ zero] , dp[i-1][j-a[i]+ zero] + b[i]);}}int ans = 0;for(int j = 100000; j>=0; j--) {if(dp[tot][j+ zero] >= 0) ans = max(ans, dp[tot][j+ zero] + j);}printf("%d\n",ans);return 0 ;}
或者这样也可以过:(空间162.9MB)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
int tot;
int a[MAX],b[MAX];
int dp[105][400000 + 5];//截止到第i个,a[i]和为j的情况下,b[i] 的最大值
int zero = 100000;
const int INF = 0x3f3f3f3f;
int main()
{int n;cin>>n;for(int x,y,i = 1; i<=n; i++) {scanf("%d%d",&x,&y);if(x < 0 && y < 0) continue;a[++tot] = x, b[tot] = y;} for(int i = 0; i<=tot; i++) {for(int j = -100000; j<=300000; j++) {//这里变了dp[i][j+ zero] = -INF;}}for(int i = 1; i<=tot; i++) {dp[i][a[i]+ zero] = b[i];}for(int i = 2; i<=tot; i++) {for(int j = -100000; j<=100000; j++) {if(dp[i-1][j+ zero] != -INF) dp[i][j+ zero] = max(dp[i][j+zero],dp[i-1][j+ zero]);if(j - a[i] + zero >= 0 )//这里变了dp[i][j+ zero] = max(dp[i][j+ zero] , dp[i-1][j-a[i]+ zero] + b[i]);}}int ans = 0;for(int j = 100000; j>=0; j--) {if(dp[tot][j+ zero] >= 0) ans = max(ans, dp[tot][j+ zero] + j);}printf("%d\n",ans);return 0 ;}
或者这样:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
int tot;
int a[MAX],b[MAX];
int dp[105][400000 + 5];//截止到第i个,a[i]和为j的情况下,b[i] 的最大值
int zero = 100000;
const int INF = 0x3f3f3f3f;
int main()
{int n;cin>>n;for(int x,y,i = 1; i<=n; i++) {scanf("%d%d",&x,&y);if(x < 0 && y < 0) continue;a[++tot] = x, b[tot] = y;} for(int i = 0; i<=tot; i++) {for(int j = -100000; j<=300000; j++) {dp[i][j+ zero] = -INF;}}dp[0][zero] = 0;
// for(int i = 1; i<=tot; i++) {
// dp[i][a[i]+ zero] = b[i];
// }for(int i = 1; i<=tot; i++) {for(int j = -100000; j<=100000; j++) {if(dp[i-1][j+ zero] != -INF) dp[i][j+ zero] = max(dp[i][j+zero],dp[i-1][j+ zero]);if(j - a[i] + zero >= 0 )dp[i][j+ zero] = max(dp[i][j+ zero] , dp[i-1][j-a[i]+ zero] + b[i]);}}int ans = 0;for(int j = 100000; j>=0; j--) {if(dp[tot][j+ zero] >= 0) ans = max(ans, dp[tot][j+ zero] + j);}printf("%d\n",ans);return 0 ;}
当然,如果你连if(j - a[i] + zero >= 0 )也不想写,那就可以直接ZERO设为200000就行了。
总结:
首先需要知道他和0-1背包还是有区别的,因为0-1背包是可以不初始化成-INF的,但是那样表示的是可以表示的最大价值(因为价值都是正数),所以0可以当成是非法状态。而这个题,必须初始化成-INF,因为这题所谓的“价值”可以是负数,我们需要新设置一个非法状态,并且把唯一一个合法状态设置好dp[0][zero]=0;来方便后面的转移。其实这样说来,就可以改成一维的0-1背包了。
错误代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
int tot;
int a[MAX],b[MAX];
int dp[400000 + 5];//截止到第i个,a[i]和为j的情况下,b[i] 的最大值
int zero = 100000;
const int INF = 0x3f3f3f3f;
int main()
{int n;cin>>n;for(int x,y,i = 1; i<=n; i++) {scanf("%d%d",&x,&y);if(x < 0 && y < 0) continue;a[++tot] = x, b[tot] = y;} for(int j = -100000; j<=300000; j++) {dp[j+ zero] = -INF;}dp[zero] = 0;for(int i = 1; i<=tot; i++) {for(int j = 100000; j>=-100000; j--) {if(j - a[i] + zero >= 0) dp[j+ zero] = max(dp[j+ zero] , dp[j-a[i]+ zero] + b[i]);}}int ans = 0;for(int j = 100000; j>=0; j--) {if(dp[j+ zero] >= 0) ans = max(ans, dp[j+ zero] + j);}printf("%d\n",ans);return 0 ;}
但是仔细一想,这样是错误的,因为就地滚动的前提是,后面的数只能用到前面的数,而你这个题,a[i]有正有负,所以可能用到前面的状态也可能用到后面的状态,所以不能优化成一维。
【蓝桥杯官网试题 - 算法提高 】求最大值 (dp,0-1背包)相关推荐
- 【蓝桥杯官网试题 - 算法提高 】P0404(模拟)
题干: 计算一个无符号整数的阿尔法乘积.对于一个无符号整数x来说,它的阿尔法乘积是这样来计算的:如果x是一个个位数,那么它的阿尔法乘积就是它本身:否则的话,x的阿尔法乘积就等于它的各位非0的数字相乘所 ...
- 【蓝桥杯官网试题 - 算法训练 】K好数(线性dp与优化)
题干: 问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数.求L位K进制数中K好数的数目.例如K = 4,L = 2的时候,所有K好数为11.13.2 ...
- 【蓝桥杯官网试题 -算法训练】素因子去重(数学,数论,因子约数)
题干: 问题描述 给定一个正整数n,求一个正整数p,满足p仅包含n的所有素因子,且每个素因子的次数不大于1 输入格式 一个整数,表示n 输出格式 输出一行,包含一个整数p. 样例输入 1000 样例输 ...
- 【蓝桥杯官网试题 - 算法训练 】P0502(乱搞,tricks)
题干: 编写一个程序,读入一组整数,这组整数是按照从小到大的顺序排列的,它们的个数N也是由用户输入的,最多不会超过20.然后程序将对这个数组进行统计,把出现次数最多的那个数组元素值打印出来.如果有两个 ...
- 蓝桥杯官网 试题 PREV-61 历届真题 装饰珠【第十一届】【决赛】【研究生组】【C++】【C】【Java】【Python】四种解法
为帮助大家能在6月18日的比赛中有一个更好的成绩,我会将蓝桥杯官网上的历届决赛题目的四类语言题解都发出来.希望能对大家的成绩有所帮助. 今年的最大目标就是能为[一亿技术人]创造更高的价值. 资源限制 ...
- 蓝桥杯官网 试题 PREV-240 历届真题 答疑【第十一届】【决赛】【研究生组】【C++】【C】【Java】【Python】四种解法
为帮助大家能在6月18日的比赛中有一个更好的成绩,我会将蓝桥杯官网上的历届决赛题目的四类语言题解都发出来.希望能对大家的成绩有所帮助. 今年的最大目标就是能为[一亿技术人]创造更高的价值. 资源限制 ...
- 蓝桥杯官网 试题 PREV-109 历届真题 扫地机器人【第十届】【省赛】【研究生组】【C++】【Java】【Python】三种解法
为帮助大家能在6月18日的比赛中有一个更好的成绩,我会将蓝桥杯官网上的历届决赛题目的四类语言题解都发出来.希望能对大家的成绩有所帮助. 今年的最大目标就是能为[一亿技术人]创造更高的价值. 资源限制 ...
- 蓝桥杯官网 试题 PREV-265 历届真题 砝码称重【第十二届】【省赛】【研究生组】【C++】【C】【Java】【Python】四种解法
为帮助大家能在6月18日的比赛中有一个更好的成绩,我会将蓝桥杯官网上的历届决赛题目的四类语言题解都发出来.希望能对大家的成绩有所帮助. 今年的最大目标就是能为[一亿技术人]创造更高的价值. 资源限制 ...
- 【蓝桥杯官网试题 - 历届试题】格子刷油漆(dp)
题干: 问题描述 X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆. 你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但 ...
最新文章
- 推荐一款神器:在浏览器中运行 vscode,随时随地写代码
- 水波纹效果,附工程源码
- 鸿蒙系统突破,华为解锁新成就!新系统用户突破1亿,鸿蒙系统也传来了新消息...
- 非标准化的阀门企业也在用钉钉宜搭实现数字化转型
- 业界萌新对斯坦纳树的小结
- 趣学java,编程趣学习app
- python多线程基本操作
- ListView的两种使用方法--Android学习笔记
- 分表扩展全局序列原理_高可用_单表存储千万级_海量存储_分表扩展---MyCat分布式数据库集群架构工作笔记0025
- cnforyou被收购了,没地方买书了
- LINUX下system和execl有什么差异?
- 使用百度图像识别时,提示错误“No address associated with hostname”
- 一款完全仿照E盾的源码(服务端+代理端+客户端)
- iphone与计算机连接,将 iPhone 与电脑同步
- Clonezilla制作镜像、恢复
- 书单 | 测试工程师必读经典好书,你读过几本?
- 大数据课程——Spark SQL
- 史上最全量化交易资源整理(转)
- 百度快速收录我的网站-百度推送软件免费
- 计算机专业省赛一等奖有什么好处,竞赛省一等奖有什么用
热门文章
- 第七课 循环神经网络与自然语言处理
- [计算机网络][总结][常见问题][TCP][三次握手][四次挥手]
- 计算机二级1605错误,word 出现windows installer 1605错误
- java 数据库连接池 开源_开源自己开发的一个JAVA数据库连接池,效果还算可以。...
- svn不知道这样的主机 怎么解决_家里装修不知道怎么配置净水器,这几招教你轻松解决...
- c语言中的取模运算符_C语言除法算法和取模运算的实现(多种算法,多种思路)...
- php异步轮询如何实现,深入剖析JavaScript异步之事件轮询
- 标准正态分布表_表达矩阵的归一化和标准化,去除极端值,异常值
- kcbzps oracle_Oracle 11g DRCP配置与使用(上)
- error C4668: 没有将“_WIN32_WINNT_WIN10_TH2”定义为预处理器宏,用“0”替换“#if/#elif”