【动态规划】SSL_1322 清兵线

探讨在数轴上清除士兵以最大化金币收益的策略。通过动态规划算法,分析了清兵路径的选择与金币获取之间的关系,提出了一种有效的算法实现。

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

题意

在一个数轴上有一些小兵,每个小兵在一个单位时间会减少一滴血量,清一个兵得到的金币为这个兵剩下的血量,求从原点如何清兵会得到尽量多的金币。

思路

因为清兵要么一直往一个方向走,要么清到一半退回来,所以我们可以设fi[i][j][k]为当前要清kkk个兵,已经清了i∼ji\sim jij的兵,当前在第iii个兵上的最多金币,可以得出动态转移方程:
fi[i][j]=max(f[i+1][j]+m−(a[i+1]−a[i])∗(k−j+i),fj[i+1][j]+m−(a[j]−a[i])∗(k−j+i)fi[i][j]=max(f[i+1][j] + m - (a[i + 1] - a[i]) * (k - j + i), fj[i + 1][j] + m - (a[j] - a[i]) * (k - j + i)fi[i][j]=max(f[i+1][j]+m(a[i+1]a[i])(kj+i),fj[i+1][j]+m(a[j]a[i])(kj+i)
代表继续往一个方向清,或者从jjj折回来清。
fjfjfj的求法同理,最后在两个方法内求最大值。
具体细节结合题目和代码。

代码

#include<cstdio>
#include<algorithm>

int n, m, ans;
int a[301], fi[301][301], fj[301][301];

int main() {
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	std::sort(a + 1, a + n + 1);
	for (int k = 1; k <= n; k++) {
		for (int i = 1; i <= n; i++)
			fi[i][i] = fj[i][i] = m - abs(a[i]) * k;
		for (int len = 2; len <= k; len++)
			for (int i = 1; i + len - 1 <= n; i++) {
				int j = i + len - 1;
				fi[i][j] = std::max(fi[i + 1][j] + m - (a[i + 1] - a[i]) * (k - j + i), fj[i + 1][j] + m - (a[j] - a[i]) * (k - j + i));
				fj[i][j] = std::max(fj[i][j - 1] + m - (a[j] - a[j - 1]) * (k - j + i), fi[i][j - 1] + m - (a[j] - a[i]) * (k - j + i));
			}
		for (int i = 1; i + k - 1 <= n; i++)
			ans = std::max(std::max(fi[i][i + k - 1], fj[i][i + k - 1]), ans);
	}
	printf("%d", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值