P2347 NOIP1996 提高组 砝码称重

1|0P2347 NOIP1996 提高组 砝码称重

1|0最初思路

看出来是多重背包,但是第一次用于求方案数,一开始想的是累加。但是实现起来发现结果很抽象,想想也不是那么回事。比如从样例上来说,F[3] = 1F[2] = 1F[1] = 1,显然F[3] != F[1] + F[2]

1|0改进思路

然后受到启发,决定用打标记的思想,即若重量j是可行的,就用F[j]标记,然后用动态规划转移这些标记。

F[J] = F[j - w[i]] ? 1 : 0

思路其实是正确的,但是代码实现出了很多问题。

1|0代码实现

1|08ptscode
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int v[7], w[7] = {0, 1, 2, 3, 5, 10, 20}; int F[1010]; int sum = 0; int ans; int main() { for (int i = 1; i <= 6; i++) { cin >> v[i]; sum += v[i] * w[i]; } for (int i = 1; i <= 6; i++) { F[w[i]] = 1; } for (int i = 1; i <= 6; i++) { for (int j = sum; j >= 0; j--) { for (int k = 1; k <= v[i]; k++) { if (k * w[i] <= j) { if (F[j - k * w[i]]) ans++; } else { if (F[j]) { continue; } } } } } printf("Total=%d", ans); return 0; }
1|0首先初始化问题
  • 这是一个不能想当然的过程,我想当然把所有初始砝码重量都赋值为1。
  • 直到在每次ans++时调试输出j才发现问题,最终总结出应把F[0] = 1即可。
1|0if顺序问题
  • 本题的F[j]是完全有可能在j>=kw[i]时也被标记过的,因为这是标记该重量可行,答案只需统计一次,而if (F[j]) continue;则是为了避免重复统计答案,但是该语句放到else后则无法处理j>=kw[i]F[j]被标记过的情况。
1|0ACcode
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int v[7], w[7] = {0, 1, 2, 3, 5, 10, 20}; int F[1010]; int sum = 0; int ans; int main() { for (int i = 1; i <= 6; i++) { cin >> v[i]; sum += v[i] * w[i]; } F[0] = 1; for (int i = 1; i <= 6; i++) { for (int j = sum; j >= 0; j--) { for (int k = 1; k <= v[i]; k++) { if (F[j]) { continue; } if (k * w[i] <= j) { if (F[j - k * w[i]]) F[j] = 1, ans++; } } } } printf("Total=%d", ans); return 0; }

__EOF__

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