正经·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. 新人上手:如何做好一个App的推广?

    App推广是现在所有公司都绕不开的槛,而一般App推广又分为线上线下两个方面,其中,App线上推广是互联网时代运营人员接触最多的一种推广方式.一款App应用推广的最终目的是为了吸引目标用户,为推销的产 ...

  2. 1. Scala概述

    1.1 概述 联邦理工学院洛桑(EPFL)的Martin Odersky于2001年开始设计Scala Scala是Scalable Language的简写,是一门多范式的编程语言 1.2 Scala ...

  3. oracle DML语句 事务的定义与特点

    1.insert into (插入数据) insert in to  表名(列表1,列表2)    values(要插入的数据1,数据2); or insert into 表名   values(数据 ...

  4. VUE-004-禁止修改页面显示项,设置el-input,textarea只读方法

    在实际业务需求中,有些内容当初次创建后,即不可再次进行修改变更,因而需要显示的文本内容不允许变更.此时,可通过页面限制防止用户修改. 方法:添加 readonly="true" 或 ...

  5. 批量将PowerDesigner中表字段由小写变成大写

    通过以下VB脚本即可批量修改,在Tools=>Execute Commands下的Edit/Run Scripts,或者通过Ctrl+Shift+X运行以下脚本即可: '************ ...

  6. spring-boot logback配置

    接着上篇的代码,日志在不同环境下的配置也不一样,所以要分开配置,主要使用maven的profile 1.1 在pom.xml中添加 <profiles> <profile> & ...

  7. chrome通过devtools来查看Devtools Extension与浏览器内核实际通信的数据情况

    1.chrome通过devtools来查看Devtools Extension与浏览器内核实际通信的数据情况,步骤如下: (1)开启开发者工具实验模式 ---浏览器进入chrome://flags - ...

  8. 2018-2019-2 20175211 实验二《Java面向对象程序设计》实验报告

    目录 代码托管 一.单元测试 (1)三种代码 二.TDD(Test Driven Development,测试驱动开发) 三.面对对象三要素 四.练习 五.问题及解决 六.PSP 代码托管 一.单元测 ...

  9. 谷歌将一些弱小的库从安卓代码移除Google Removes Vulnerable Library from Android

    Google this week released the November 2018 set of security patches for its Android platform, which ...

  10. elasticsearch开机启动脚本

    最近搭建了一个elasticsearch服务,其中机器重启而ES服务没有重启是问题,就有下面的脚本 #!/bin/sh #chkconfig: #description: es export JAVA ...