P5322 BJOI2019 排兵布阵

1|0P5322 BJOI2019 排兵布阵

1|1基本思路

一眼背包,然后无脑套01,样例也过了,直接提交,40pts。

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int M = 50010; int s, n, m; int F[M]; int w; int main() { cin >> s >> n >> m; for (int i = 1; i <= s; i++) { for (int j = 1; j <= n; j++) { cin >> w; for (int k = m; k >= w * 2 + 1; k--) { F[k] = max(F[k], F[k - w * 2 - 1] + j); } } } cout << F[m]; return 0; }

1|2改进思路

1|0状态转移方程出问题

如果击败一个更多士兵的对手,比他士兵少的对手本应是一并击败并得分的,但我的方程只能计算击败的一个对手的分数。

理解上面这点,实际上就可以运用排序,先给每个地堡对应的每个人的士兵数进行排序,然后问题就转化成了对n个地堡的分组背包问题,每个地堡选择一个人击败,获得击败所有小于等于这个人士兵数的奖励

1|0代码实现问题

因为不怎么写分组背包,代码实现还是出了问题。

一开始是这样写的,但是死活跑不过样例。

for (int k = 1; k <= n; k++) { for (int i = 1; i <= s; i++) { for (int j = m; j >= w[k][i]; j--) { F[j] = max(F[j], F[j - w[k][i] * 2 - 1] + k * i); } } }

实际上这个嵌套无法进行分组背包的过程。

带入内层循环很容易复发现,因为背包容量J是在每组的人员i内层枚举,导致这本质上还是零一背包,无法保证每组只选择一个。

改进方式很简单,把背包容量J是在地堡数量k下一层枚举即可。

for (int k = 1; k <= n; k++) { for (int j = m; j >= 0; j--) { for (int i = 1; i <= s; i++) { if (j > w[k][i] * 2) F[j] = max(F[j], F[j - w[k][i] * 2 - 1] + k * i); } } }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/17817794.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示