2020杭电多校2 1010 Lead of Wisdom

本文探讨了一个关于装备选择的问题,目标是在限定条件下选出装备组合以最大化最终伤害值。通过暴力搜索结合优化策略,解决了数据规模不大但需高效求解的挑战。文章详细分析了算法设计与优化过程,包括如何有效避免无效搜索,显著提升算法效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

在这里插入图片描述
题目链接

题目大意是每组给定n个装备,每个装备属于一个类别,并有四个属性a,b,c,d。每个类别仅允许挑选一个装备最终伤害值为所有选定装备的四个属性分别与100求和再相乘。问最大值为多少

暴力搜索+优化

看完题目,满脑子都是暴力搜索,一看数据规模,n <= 50。

推算一下搜索的复杂度,最坏情况是装备均分到每个组,则有如下复杂度分析:

在这里插入图片描述
316方有多少呢?大概是:

在这里插入图片描述
完全可以接受,没有问题。

于是美美的交了第一发暴力:

#include<iostream>
#include<cstdio>
#define N 55
using namespace std;
int item[N][N];
int t,n,K;
int a[N];
int b[N];
int c[N];
int d[N];
long long ans;

void dfs(int k,int sumA,int sumB,int sumC,int sumD){
	if(k > K){
		long long temp = 1LL * sumA * sumB * sumC * sumD;
		ans = ans >  temp ? ans : temp;
		return; 
	}
	if(item[k][0] == 0){
		dfs(k + 1,sumA,sumB,sumC,sumD);
		return;
	}
	for(int i = 1;i <= item[k][0];i++){
		dfs(k + 1,sumA + a[item[k][i]],sumB + b[item[k][i]],sumC + c[item[k][i]],sumD + d[item[k][i]]);
	}
}

int main(){
	for(cin >> t;t;t--){
		ans = 0;
		scanf("%d%d",&n,&K);
		for(int i = 1;i <= K;i++){
			item[i][0] = 0;
		}
		for(int i = 1,ki;i <= n;i++){
			scanf("%d",&ki);
			item[ki][++item[ki][0]] = i;
			scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
		}
		dfs(1,100,100,100,100);
		printf("%lld\n",ans);

	}
}

于是妥妥的tle,淦。

仔细思考发现,对于没有装备的组来说,单单在搜索时到下一层是不合适的,每次枚举都会遍历这些层,所以最终的复杂度就变成了O(n3n/3)。
上面的4 * 107 再乘上 n = 50 那就是 50 * 4 * 107 = 2 * 109那可是要超时。。。。。。

所以对于没有装备的分组来说,应该直接跳过,而不是让它走下一层。这个预处理一个nxt数组指向下一个非零的组编号即可:

ac代码

#include<iostream>
#include<cstdio>
#define N 55
using namespace std;
int item[N][N];
int cnt[N];
int t,n,K;
int a[N];
int b[N];
int c[N];
int d[N];
int nxt[N];
long long ans;

void dfs(int k,int sumA,int sumB,int sumC,int sumD){
	if(k > K){
		long long temp = 1LL * sumA * sumB * sumC * sumD;
		ans = ans >  temp ? ans : temp;
		return; 
	}
	if(cnt[k] == 0){
		dfs(nxt[k],sumA,sumB,sumC,sumD);
		return;
	}
	for(int i = 1;i <= cnt[k];i++){
		dfs(k + 1,sumA + a[item[k][i]],sumB + b[item[k][i]],sumC + c[item[k][i]],sumD + d[item[k][i]]);
	}
}

int main(){
	scanf("%d",&t);
	while(t--){
		ans = 0;
		scanf("%d%d",&n,&K);
		for(int i = 1;i <= K;i++){
			cnt[i] = 0;
		}
		for(int i = 1,ki;i <= n;i++){
			scanf("%d",&ki);
			item[ki][++cnt[ki]] = i;
			scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
		}
		
		for(int i = K,nx = K + 1;i >= 1;i--){
			nxt[i] = nx;
			if(cnt[i]) nx = i;
		}
		
		dfs(1,100,100,100,100);
		printf("%lld\n",ans);
	}
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值