问题描述
给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
01背包变种,复制一下别人的思路:
不直接计算选定的数的ai+bi的和,而是转化为计算在ai的和一定的情况下尽量使选定的bi的和最大。于是变成为一个和01背包差不多的问题。首先过滤掉所有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])。为避免负数作为数组下标,要加一个偏移量。
1 #include<stdio.h> 2 3 #define Max(a,b) ((a>b)?(a):(b)) 4 #define N 100000 5 6 void input( int [] , int [] , int ); 7 int maxNum( int [] , int [] , int ); 8 9 int main(void) 10 { 11 int n ; 12 scanf("%d" , &n ); 13 14 int Na[n] , Nb[n] ; 15 input( Na , Nb , n ); 16 17 int ans = maxNum( Na , Nb , n ); 18 printf("%d\\n", ans >= 0 ? ans : 0 ); 19 return 0; 20 } 21 22 void input( int Na[] , int Nb[] , int n ){ 23 while( n -- ){ 24 scanf("%d%d", Na ++ , Nb ++ ); 25 } 26 } 27 28 int maxNum( int Na[] , int Nb[] , int n ){ 29 static int dp[100][N*2+1] = {0} ; 30 int res = -N ; 31 int i , j ; 32 for( i = 0 ; i < n ; i ++ ){ 33 for( j = -N ; j <= N ; j ++ ){ 34 dp[i][j + N] = -N ; 35 } 36 } 37 38 for( i = 0 ; i < n ; i ++ ){ 39 dp[i][N + Na[i]] = Nb[i] ; 40 } 41 42 for( i = 1 ; i < n ; i ++ ){ 43 for( j = -N ; j <= N ; j ++ ){ 44 dp[i][j + N] = Max(dp[i][j + N] , dp[i-1][j + N]); 45 46 if( j + N - Na[i] >= 0 && j + N - Na[i] < N*2 ){ 47 dp[i][j + N] = Max( dp[i][j + N] , dp[i-1][j + N - Na[i]] + Nb[i] ); 48 } 49 } 50 } 51 52 for( j = 0 ; j <= N ; j ++ ){ 53 if( dp[n-1][j + N] >= 0 ){ 54 res = Max( res , j + dp[n-1][j + N] ); 55 } 56 } 57 58 return res; 59 }