暴搜优化.
分析:
令第 i 种装备的数量为sum[i],显然如果 sum[i]不为 0 那么这种装备必选一件,在这时需要考虑的总方案数为 ∏
max(sum[i], 1),其中 ∑sum[i] ≤ 50。最坏情况下所有
sum 的值都相同,令它们都等于 k,则方案数为 kn/k ,当 k 取 3 时取到最大值 3n/3 ,在 n = 50 时
并不算太大,因此可以直接爆搜所有方案得到最优解。
需要注意的是,sum[i] = 0 的部分应该直接跳过,以保证搜索树上每一层的节点数至少是上一层的两倍,使得时间复杂度为 O(3n/3 ),否则会退化成 O(n*3n/3) 而 TLE。
#include <bits/stdc++.h>
#define ll long long
#define T int t;scanf("%d", &t);while(t--)
using namespace std;
int dx[]={0,0,-1,1};
int dy[]={1,-1,0,0};
const ll mod = 1e9+7;
const int maxn = 2e5+5;
ll ans = 0;
int n,m;
int f[55][55][5];
int nxt[55];
int sum[55];
void dfs(int k, int a, int b, int c, int d){
if(k > m){
ll cnt = 1ll * a * b * c * d;
ans = max(cnt,ans);
return;
}
int num = sum[k];
//如果当前种装备数量为0,直接搜下一种数量不为0的装备种类
if(num == 0){
dfs(nxt[k],a,b,c,d);
return;
}
for(int i = 1; i <= num; i ++){
dfs(k + 1, a + f[k][i][1], b + f[k][i][2], c + f[k][i][3], d + f[k][i][4]);
}
}
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%d %d", &n, &m);
int k;
memset(sum,0,sizeof(sum));
while(n--){
scanf("%d", &k);
sum[k]++; //第k种装备的数量
for(int i = 1; i <= 4; i++)
scanf("%d", &f[k][sum[k]][i]); //四种属性值
}
k = m + 1;
//核心代码,记录下一种数量不为0的装备是哪种
for(int i = m; i > 0; i --){
nxt[i] = k;
if(sum[i]) k = i;
}
ans = 0;
dfs(1,100,100,100,100);
printf("%lld\n", ans);
}
return 0;
}