题干:
问题描述
给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
#include
#include
#include
#include
或者这样也可以过:(空间162.9MB)
#include
#include
#include
#include
#include
或者这样:
#include
#include
#include
#include
#include
当然,如果你连if(j - a[i] + zero >= 0 )也不想写,那就可以直接ZERO设为200000就行了。
总结:
首先需要知道他和0-1背包还是有区别的,因为0-1背包是可以不初始化成-INF的,但是那样表示的是可以表示的最大价值(因为价值都是正数),所以0可以当成是非法状态。而这个题,必须初始化成-INF,因为这题所谓的“价值”可以是负数,我们需要新设置一个非法状态,并且把唯一一个合法状态设置好dp[0][zero]=0;来方便后面的转移。其实这样说来,就可以改成一维的0-1背包了。
错误代码:
#include
#include
#include
#include
#include
但是仔细一想,这样是错误的,因为就地滚动的前提是,后面的数只能用到前面的数,而你这个题,a[i]有正有负,所以可能用到前面的状态也可能用到后面的状态,所以不能优化成一维。