直观上觉得应该优先选取b大的那个数字,这样a就不会下降的太快,但是这种情况仅仅适用于n=m的时候。因为我们需要的是m个数字的a值之和是最大的,当n>m时,如果直接选取了下降速度最快(即b最大)的那m个数字,有可能后面的数的a值可能仍然很大,但b值却很少,这样就不能保证这m个数的a值之和是最大的(而当n=m是却不存在这个问题)。
从另一个角度看,问题的本质在于选取哪m个数字,也即是该不该选取某一个数字,这明显是01背包的特点。当使用一维数组来解决这个问题时,鉴于数组上的数据是覆盖保存的,首先就要对每个数字按b值从大到小进行排序,从而确保迭代过程中的数据都是目前最优的。状态转移方程则是:score[j]=max(score[j],score[j-1]+a[i]-b[i]*(j-1)),理解为对于第i个数字,当要选取j个数字时,最优结果是:不选取这个数字,从剩下的数字中再选取j个数字的最优结果;或者是选取这个数字,从剩下的数字中再选取j-1个数字的最优结果。以上两者的更优者就是最优解。如此进行下去,score[m]就是最终解。
Run Time: 0sec
Run Memory: 312KB
Code Length: 707Bytes
SubmitTime: 2012-02-13 16:17:25
// Problem#: 1221
// Submission#: 1210144
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <iostream>
#include <algorithm>
using namespace std;
struct Num {
int a;
int b;
};
bool cmp( const Num& n1, const Num& n2 ) { return n1.b > n2.b; }
int main()
{
int n, m;
Num num[ 201 ];
int score[ 201 ];
int i, j;
cin >> n >> m;
for ( i = 1; i <= n; i++ )
cin >> num[ i ].a;
for ( i = 1; i <= n; i++ )
cin >> num[ i ].b;
sort( num + 1, num + n + 1, cmp );
for ( i = 0; i <= m; i++ )
score[ i ] = 0;
for ( i = 1; i <= n; i++ ) {
for ( j = m; j >= 1; j-- )
score[ j ] = max( score[ j ], score[ j - 1 ] + num[ i ].a - num[ i ].b * ( j - 1 ) );
}
cout << score[ m ] << endl;
return 0;
}