分析:
1、用 vector<int> v[i] 来存 i 城堡, s 个对手所安排的士兵数量。
2、设 dp[i][j] 表示 i 城堡前,在当前最大派兵量为 j 时所能获得的最大价值。
3、不难想到的是,遍历 s 个对手,再用两个 for 遍历一下该城堡中各个对手的派兵量。然后对于能派的就派去看看能否更新 dp 值。
4、再者我们考虑贪心思想:若第 i 个城堡中, A 选手派出 a 个兵,那至少需要派 2 * a + 1个兵才能对答案有贡献;再者若 B 选手派出 b 个兵,且 b > a ,那么如果能派出 2 * b + 1 个兵的话,则对于 A 选手那边也可以做出贡献。故我们需要使 v[i] 进行排序,这样 dp 时如果后面大的能满足,那么直接使得 (当前以上的选手数量) * i ,得出当前城堡的贡献即可。
此算法的时间复杂度为 O(nms),看上去达到 2 * 108 ,但在 dp 中会有 break 来剪枝 。
此外由于转移方程中只与上一层即 dp[i - 1][] 有关,故可降到一维。
代码如下:
#define IO freopen("test.in","r",stdin),freopen("test.out","w",stdout)
#define inf 0x3f3f3f3f
#define lson root<<1
#define rson root<<1|1
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
int s,n,m;
int a[108],dp[20008];
vector<int> v[108];
int main()
{
//IO;
scanf("%d%d%d",&s,&n,&m);
for(int i=1;i<=n;i++) a[i]=inf;
int A;
for(int i=1;i<=s;i++){
for(int j=1;j<=n;j++){
scanf("%d",&A);
v[j].push_back(A);
a[j]=min(a[j],A);
}
}
for(int i=1;i<=n;i++) sort(v[i].begin(),v[i].end());
for(int i=1;i<=n;i++){
for(int j=m;j>a[i]*2;j--){
for(int k=0;k<v[i].size();k++){
if(j<=v[i][k]*2) break;
dp[j]=max(dp[j],dp[j-(v[i][k]*2+1)]+(k+1)*i);
}
}
}
printf("%d\n",dp[m] );
}
知识兔