题干:

问题描述

  给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背包)相关推荐

  1. 【蓝桥杯官网试题 - 算法提高 】P0404(模拟)

    题干: 计算一个无符号整数的阿尔法乘积.对于一个无符号整数x来说,它的阿尔法乘积是这样来计算的:如果x是一个个位数,那么它的阿尔法乘积就是它本身:否则的话,x的阿尔法乘积就等于它的各位非0的数字相乘所 ...

  2. 【蓝桥杯官网试题 - 算法训练 】K好数(线性dp与优化)

    题干: 问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数.求L位K进制数中K好数的数目.例如K = 4,L = 2的时候,所有K好数为11.13.2 ...

  3. 【蓝桥杯官网试题 -算法训练】素因子去重(数学,数论,因子约数)

    题干: 问题描述 给定一个正整数n,求一个正整数p,满足p仅包含n的所有素因子,且每个素因子的次数不大于1 输入格式 一个整数,表示n 输出格式 输出一行,包含一个整数p. 样例输入 1000 样例输 ...

  4. 【蓝桥杯官网试题 - 算法训练 】P0502(乱搞,tricks)

    题干: 编写一个程序,读入一组整数,这组整数是按照从小到大的顺序排列的,它们的个数N也是由用户输入的,最多不会超过20.然后程序将对这个数组进行统计,把出现次数最多的那个数组元素值打印出来.如果有两个 ...

  5. 蓝桥杯官网 试题 PREV-61 历届真题 装饰珠【第十一届】【决赛】【研究生组】【C++】【C】【Java】【Python】四种解法

    为帮助大家能在6月18日的比赛中有一个更好的成绩,我会将蓝桥杯官网上的历届决赛题目的四类语言题解都发出来.希望能对大家的成绩有所帮助. 今年的最大目标就是能为[一亿技术人]创造更高的价值. 资源限制 ...

  6. 蓝桥杯官网 试题 PREV-240 历届真题 答疑【第十一届】【决赛】【研究生组】【C++】【C】【Java】【Python】四种解法

    为帮助大家能在6月18日的比赛中有一个更好的成绩,我会将蓝桥杯官网上的历届决赛题目的四类语言题解都发出来.希望能对大家的成绩有所帮助. 今年的最大目标就是能为[一亿技术人]创造更高的价值. 资源限制 ...

  7. 蓝桥杯官网 试题 PREV-109 历届真题 扫地机器人【第十届】【省赛】【研究生组】【C++】【Java】【Python】三种解法

    为帮助大家能在6月18日的比赛中有一个更好的成绩,我会将蓝桥杯官网上的历届决赛题目的四类语言题解都发出来.希望能对大家的成绩有所帮助. 今年的最大目标就是能为[一亿技术人]创造更高的价值. 资源限制 ...

  8. 蓝桥杯官网 试题 PREV-265 历届真题 砝码称重【第十二届】【省赛】【研究生组】【C++】【C】【Java】【Python】四种解法

    为帮助大家能在6月18日的比赛中有一个更好的成绩,我会将蓝桥杯官网上的历届决赛题目的四类语言题解都发出来.希望能对大家的成绩有所帮助. 今年的最大目标就是能为[一亿技术人]创造更高的价值. 资源限制 ...

  9. 【蓝桥杯官网试题 - 历届试题】格子刷油漆(dp)

    题干: 问题描述 X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆. 你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但 ...

最新文章

  1. 推荐一款神器:在浏览器中运行 vscode,随时随地写代码
  2. 水波纹效果,附工程源码
  3. 鸿蒙系统突破,华为解锁新成就!新系统用户突破1亿,鸿蒙系统也传来了新消息...
  4. 非标准化的阀门企业也在用钉钉宜搭实现数字化转型
  5. 业界萌新对斯坦纳树的小结
  6. 趣学java,编程趣学习app
  7. python多线程基本操作
  8. ListView的两种使用方法--Android学习笔记
  9. 分表扩展全局序列原理_高可用_单表存储千万级_海量存储_分表扩展---MyCat分布式数据库集群架构工作笔记0025
  10. cnforyou被收购了,没地方买书了
  11. LINUX下system和execl有什么差异?
  12. 使用百度图像识别时,提示错误“No address associated with hostname”
  13. 一款完全仿照E盾的源码(服务端+代理端+客户端)
  14. iphone与计算机连接,将 iPhone 与电脑同步
  15. Clonezilla制作镜像、恢复
  16. 书单 | 测试工程师必读经典好书,你读过几本?
  17. 大数据课程——Spark SQL
  18. 史上最全量化交易资源整理(转)
  19. 百度快速收录我的网站-百度推送软件免费
  20. 计算机专业省赛一等奖有什么好处,竞赛省一等奖有什么用

热门文章

  1. 第七课 循环神经网络与自然语言处理
  2. [计算机网络][总结][常见问题][TCP][三次握手][四次挥手]
  3. 计算机二级1605错误,word 出现windows installer 1605错误
  4. java 数据库连接池 开源_开源自己开发的一个JAVA数据库连接池,效果还算可以。...
  5. svn不知道这样的主机 怎么解决_家里装修不知道怎么配置净水器,这几招教你轻松解决...
  6. c语言中的取模运算符_C语言除法算法和取模运算的实现(多种算法,多种思路)...
  7. php异步轮询如何实现,深入剖析JavaScript异步之事件轮询
  8. 标准正态分布表_表达矩阵的归一化和标准化,去除极端值,异常值
  9. kcbzps oracle_Oracle 11g DRCP配置与使用(上)
  10. error C4668: 没有将“_WIN32_WINNT_WIN10_TH2”定义为预处理器宏,用“0”替换“#if/#elif”