题意:
给出n个5元组,从中选出k组,使得这些组中5个位置,每个位置上最大数之和最大。
分析:
想了好久…最后还是参考了别人的题解…
一到DP必死无疑
当 k > 5 的情况都好说了,都可以取到最大值;
艰难的是k < 5 的情况
由于n的范围为1,10000,所以从n考虑是很难解出来的。
于是我们从5元组考虑。
每组5元组,最后可能被选择作为和的一部分,就是[11111],即[全部被选中做和]的子集,一共有31种情况。
我们只要预处理这31种情况可能得到的最大的和。然后dfs遍历子集就行了。具体见代码。
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
const int MAXN = 1 << 5;
const int N = 5;
int sum[MAXN], arr[10005][N];
int n, k, ans;
void build(){
memset(sum, 0, sizeof(sum));
for(int i = 0; i < n; i++){
for(int j = 0; j < MAXN; j++){
int temp = 0;
for(int k = 0; k < N; k++)
if(j & ( 1 << k ))
temp += arr[i][k];
sum[j] = max(sum[j], temp);
}
}
}
void dfs(int S, int cnt, int x){
if(cnt == k){
ans = max(ans, x);
}
for( int i = S; i; i = ( i - 1)&S)
dfs(S^i, cnt + 1, x + sum[i]);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n, &k);
for( int i = 0; i < n; i++ ){
for(int j = 0; j < 5; j++)
scanf("%d",&arr[i][j]);
}
ans = 0;
if(k >= 5){
for( int i = 0; i < N; i++ ){
int temp = 0;
for( int j = 0; j < n; j++)
temp = max(temp, arr[j][i]);
ans += temp;
}
}
else {
build();
dfs(MAXN - 1, 0 ,0 );
}
printf("%d\n",ans);
}
return 0;
}