正经·DP题解

一道非常好的背包练手题(

sto(注:原思路来源 SLYZ_0120 的题解)orz

开始这道题

1.输入六个数,存进数组中
2.初始化 f 数组为0。 f [ i ] 表示重量为 i 的情况是否出现过(下面代码使用的是 int 数组,当然用 bool 数组会更好)。如果出现过即为真(1),未出现过即为假(0)。
3.这里我们要将 f [ 0 ] 设为 1 。总重量为 0 即一个砝码也不用,我们将这种情况设为已有。
4.第一重循环。

for (int i = 1 ; i <= 6 ; i++ )

我们枚举六种重量的砝码。

5.第二重循环

for (int j = 1 ; j <= a[i] ; j++ )

这里的a[i]指的是第 i 种砝码的个数。即我们进行循环的次数就是第i种砝码的个数(你是不是觉得我在说废话 但是请好好理解)

6.第三重循环

for (int k = 1000 ; k >= 0 ; k-- )

三重循环分开来或许不是很好理解。接下来我们来结合三个循环分析。

7.代码核心
for (int i=1 ; i<=6 ; i++)

    for (int j=1 ; j<=a[i] ; j++)

        for (int k=1000 ; k>=0 ; k--)
{ if (f[k]==1)
{
f[k+w[i]]=1;
} }

请按照提示看以上代码

1.首先,请简要看完三重循环并尝试初步理解。

2.看循环内部语句。

       看这两个语句时,请尝试将样例代入(建议自己设个稍微大一点点点点的样例 真的大一点点就够了 因为 1 不够特殊),从 i=1,j=1,k=1000的情况开始,尝试想想,当是这种情况时, f 数组发生了什么变化?
接着想想,当k不停的自减,会发生什么呢?
最后想想,当 i=1,j=1,k=0的时候会发生什么呢?那又代表了什么意思? 思考:循环内部的语句。
接下来,我们指的“某种重量成立”,指的是这个重量可以被称出来。(也可以说,有这么一些砝码可以组成这个重量)
其实,当六种砝码的个数都是无限的时候,因为我们有一种砝码的重量为1,所以所有重量都可以 成立 。
但是,当六种砝码的个数是有限的时候,并不是所有的重量都能够 成立 。
那么,我们的 f 数组,其实就是用于标记 “这种重量是否成立” 。 我们有这么一个状态 X , 状态 X 的砝码重量为 w 。(即重量 w 成立)
那么如果我们有一个 “未使用” 的砝码 ,其重量为 p ,那么
重量 w+p 也是成立的。(这句话请认真理解) 带着这个思路,请看向循环 “k=1000……” 以及 循环内部的语句 。
这里的 k ,其实就是刚刚所提到的重量 w 。
f [ k ] == 1 ,就是重量 k 成立的意思 。那么我们加上 w [ i ] (相当于刚刚的 p ),即第i种砝码的重量,那么得到的重量依然是成立的。

3.请看向第二个循环语句

        顺着我们上一条的思路。
返回我们文章开头的地方,对于 j 这重循环的介绍。 “这里的 a [ i ] 指的是第 i 种砝码的个数。即我们进行循环的次数就是第i种砝码的个数”。 接着看向我们上一条中
“ 如果我们有一个 ‘未使用’ 的砝码 ” 其实在我们进行这一重循环的时候,就相当于,我们将第 i 种砝码 “摆成一排”。 对,你现在可以打大开脑洞,想着你本来有10个一样重的砝码,然后你把这些砝码在你面前整齐de放成一排—————— 现在拿起你的第一个砝码。我们开始找已知的 “成立的重量”。 找到一个成立的重量后,我们就可以确定,这个成立的重量加上你手中的这个砝码也是一个成立的重量。那么我们将新的 “成立的重量” 标记。 现在拿起你的第二个砝码。我们继续找已知的 “成立的重量”。 注意,这时成立的重量,包含了我们刚刚拿第一个砝码时标记的 “新的成立的重量”。接下来的步骤类似上面。 ……………… 刚刚的砝码用完了,
接着,你又拿出了跟刚才不同重量的另外10个一样重的砝码,摆成一排……
接下来发生了什么也类似上面。 当你把所有的砝码都用完的时候,所有被标记的 “成立的重量”,就是使用这些砝码的所有 “成立的重量” ! 最后,只要一遍扫过去 ~ 统计有多少种成立的重量就可以啦 ~

4.请思考:为什么 k 要从 1000 到 1 而不是 1 到 1000 呢?

        如果这个问题你一下子想不明白,那你可以先试着将下面的完整代码复制,把 for (int k=1000;k>=0;k--) 改成 for (int k=0;k<=1000;k++) ,再测一下样例,看一下结果是多少。

        如果你还没想清楚:惊不惊喜!意不意外!答案居然是1000!

        以样例为例子,我们可以想到,当 k=0 的时候, f[1] 就会被标记为成立。但接下来,当 k=1 的时候,f [2] 也会被标记为成立。那么是不是一遍扫过去,f [1~1000] 全部都被标记为成立了呢!

        在本题中,对于一个成立的重量 w ,一个砝码的重量 p ,w+p 一定大于 w。
所以这样就会造成 一个砝码使用多次的情况 (请认真体会 就是我们前一条所说的 “当六种砝码的个数都是无限的时候,因为我们有一种砝码的重量为1,所以所有重量都可以 成立 。”

完整代码

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN=1001;
int a[7],w[7]={0,1,2,3,5,10,20},f[MAXN]={};//a数组存放的是每种砝码的数量,w数组是每种砝码的重量,f[i]表示 “重量 i 成立”
int main()
{
for (int i=1;i<=6;i++)//输入
{
scanf("%d",&a[i]);
}
f[0]=1;//初始化! f [0] 就是不使用任何砝码的情况
for (int i=1;i<=6;i++)//枚举六种砝码
{
for (int j=1;j<=a[i];j++)//枚举每个砝码
{
for (int k=1000;k>=0;k--)//寻找 已成立的重量
{
if (f[k])//若此重量成立
{
f[k+w[i]]=1;//那么这个重量加上这个未使用的砝码的总重量也成立
}
}
}
}
int ans=0;
for (int i=1;i<=1000;i++)//一遍扫,统计成立的重量。记住从1开始循环,因为不使用砝码的情况在这里不统计
{
if (f[i]) ans++;
}
printf("Total=%d",ans);//输出
return 0;//华丽丽de结束!
}

给大佬们递AC!!

【题解】Luogu P2347 砝码称重的更多相关文章

  1. P2347 砝码称重(动态规划递推,背包,洛谷)

    题目链接:P2347 砝码称重 参考题解:点击进入 纪念我第一道没理解题意的题 ''但不包括一个砝码也不用的情况'',这句话我看成了每个砝码起码放一个 然后就做不出来了 思路: 1.这题数据很小,10 ...

  2. P2347 砝码称重-DP方案数-bitset

    P2347 砝码称重 DP做法 : 转化为 01背包. 进行方案数 更新.最后统计种类. #include<bits/stdc++.h> using namespace std; #def ...

  3. P2347 砝码称重

    P2347 砝码称重 题目描述 设有1g.2g.3g.5g.10g.20g的砝码各若干枚(其总重<=1000), 输入输出格式 输入格式: 输入方式:a1 a2 a3 a4 a5 a6 (表示1 ...

  4. 洛谷 P2347 砝码称重

    P2347 砝码称重 题目描述 设有1g.2g.3g.5g.10g.20g的砝码各若干枚(其总重<=1000), 输入输出格式 输入格式: 输入方式:a1 a2 a3 a4 a5 a6 (表示1 ...

  5. 洛谷P2347 砝码称重 [2017年4月计划 动态规划01]

    P2347 砝码称重 题目描述 设有1g.2g.3g.5g.10g.20g的砝码各若干枚(其总重<=1000), 输入输出格式 输入格式: 输入方式:a1 a2 a3 a4 a5 a6 (表示1 ...

  6. 洛谷 P2347 砝码称重 题解

    每日一题 day12 打卡 Analysis 完全背包 #include<iostream> #include<cstdio> #include<cstring> ...

  7. 洛谷P2347 砝码称重 【多重背包】(方案数)(经典)

    题目链接:https://www.luogu.org/problemnew/show/P2347 题目描述 设有1g.2g.3g.5g.10g.20g的砝码各若干枚(其总重<=1000), 输入 ...

  8. 洛谷——P2347 砝码称重

    https://www.luogu.org/problem/show?pid=2347#sub 题目描述 设有1g.2g.3g.5g.10g.20g的砝码各若干枚(其总重<=1000), 输入输 ...

  9. P2347 砝码称重 (01背包)

    题目描述 设有 1g1g1g . 2g2g2g . 3g3g3g . 5g5g5g . 10g10g10g . 20g20g20g 的砝码各若干枚(其总重 ≤1000 \le 1000≤1000 ), ...

随机推荐

  1. SSIS获得Excel行号(转自http://blog.csdn.net/zplume/article/details/19113911)

    问题描述: 首先个人并不推荐将Excel作为数据源,因为Excel单元格式会引起特别多的数据转换问题,例如:单元格里明明是2.89,但SSIS抽取到数据库里面之后却变成了2.88999999之类的数据 ...

  2. mysql ON DUPLICATE KEY UPDATE 与 REPLACE INTO 的区别

    #mysql ON DUPLICATE KEY UPDATE 如果在INSERT语句末尾指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY ...

  3. 尽量避免把弹窗加在window上,可以考虑把弹窗封装到控制器里面

    封装自定义弹窗,一般来说有两种选择: 在[[[UIApplication sharedApplication] delegate] window]上add自定义view: present一个模态Con ...

  4. npm是什么,用来干嘛的

    网上的 npm 教程主要都在讲怎么安装.配置和使用 npm,却不告诉新人「为什么要使用 npm」.今天我就来讲讲这个话题. 本文目标读者是「不太了解 npm 的新人」,大神您别看了,不然又说我啰嗦了 ...

  5. python基础5 while循环

    一.while循环: while  条件: 代码块 例: n=0 while n<10: print(n) n=n+1   #n自加1 ,满足n<10,继续循环 输出结果: 1 2 3 4 ...

  6. VisualStudioCode创建的asp.net core项目部署到linux,使用nginx代理

    1.准备工作: a:使用VisualStudioCode创建asp.net core项目,并使用命令“dotnet publish”发布(可以参考前面两篇文章). 如:dotnet publish - ...

  7. SVG笔记

    SVG可缩放矢量图形(Scalable Vector Graphics)是基于可扩展标记语言(XML),用于描述二维矢量图形的一种图形格式.SVG是W3C("World Wide Web C ...

  8. rpc轻量级框架实例

  9. tp5命令行

    手册->命令行->自定义命令行 1.第一步,配置command.php文件 2.第二步,建立命令类文件 注意:该文件中代码,从文档中粘,以防写错. 名字啥的都不用改,就改命名空间 和 定义 ...

  10. JMeter+Ant-自动发送测试结果报告邮件

    build.xml文件 将这三个jar包(activation.jar.commons-email-1.2.jar.mail.jar)放到ant下的lib下 (我的是:/usr/local/Cella ...