题意 : 有 n 种面额的硬币,给出各种面额硬币的数量和和面额数,求最多能搭配出几种不超过 m 的金额?

分析 :

这题可用多重背包来解,但这里不讨论这种做法。

如果之前有接触过背包DP的可以自然想到DP数组的定义 ==> dp[i][j] 表示使用前 i 种硬币是否可以凑成面额 j 。

根据这样的定义,则一开始初始化 dp[0][0] = true 最后统计 dp[n][1 ~ m] 为 true 的数量即为答案

状态转移方程为 dp[i][j] |= dp[i-1][ j - k*val[i] ] ( k 表示取 k 个第 i 种硬币、val[i] 表示第 i 种硬币的面额 )

转移方程的意义不难理解,需要考虑当前的 dp[i][j] 可以从哪些状态转移而来,如下

使用第 i 种硬币刚好凑成 j 的值应当为上个状态( dp[i-1][] )合法的 j-val[i]、j-2*val[i]、j-3*val[i]....

故代码应当为一个如下所示的三重循环,但是复杂度较高无法通过这题.....

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
;

];
int num[maxn], val[maxn];

int main(void)
{
    int N, C;
     && C==)){

        ; i<=N; i++) scanf("%d", &val[i]);
        ; i<=N; i++) scanf("%d", &num[i]);

        memset(dp, false, sizeof(dp));
        dp[][] = true;

        ; i<=N; i++){
            ; j<=C; j++){
                ; k<=num[i] && k*val[i]<=j; k++){
                    dp[i][j] |= dp[i-][j-k*val[i]];
                }
            }
        }

        printf(, dp[N]+C+, true));
    }
    ;
}

通常使用 dp 数组只记录布尔值是种浪费的做法,一般就去考虑在保证正确性的情况下改变 dp 含义记录更多信息去降低复杂度!

现将 dp 含义改变为 ==> dp[i][j] 表示用前 i 种硬币凑成 j 时第 i 种硬币最多还可以剩多少

挑战书上是直接给出了定义,但是我更乐于探寻这玩意是什么来的? 注:以下都是我自己的想法

想想上面的解法,好像会发现其实如果我当前考虑过 dp[i][j] = true 了,那么 dp[i][j+val[i]]、dp[i][j+2*val[i]]、dp[i][j+3*val[i]]... 应该都为 true

而枚举 j 的顺序也恰好是从小到大,所以必定会枚举到 dp[i][j+val[i]]、dp[i][j+2*val[i]]...,所以何不写成如下这样

; i<=N; i++){
    ; j<=C; j++){
        dp[j] |= dp[j-val[i]];
    }
}

运行了样例之后发现这样的做法得出的答案比标准答案更大!为什么?因为这样的做法没有考虑到数量,一种硬币的数量是有限的

所以当 j+k*val[i] 的 k 超过了规定数量的时候就会发生错误,使得一些本该为 false 的 dp 数组值变成了 true,所以我们需要记录数量!

复杂度为 O(n*m) 在 POJ 上跑了 2016MS

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
;

];
int num[maxn], val[maxn];

bool fun(int x)
{ ) return true; return false; }

int main(void)
{
    int N, C;
     && C==)){

        ; i<=N; i++) scanf("%d", &val[i]);
        ; i<=N; i++) scanf("%d", &num[i]);

        memset(dp, -, sizeof(dp));
        dp[] = ;

        ; i<=N; i++){
            ; j<=C; j++){
                ) dp[j] = num[i];
                ) dp[j] = -;
                ;
            }
        }

        printf(, dp++C, fun));
    }
    ;
}

POJ 1742 Coins ( 经典多重部分和问题 && DP || 多重背包 )的更多相关文章

  1. poj 1742 Coins(二进制拆分+bitset优化多重背包)

    \(Coins\) \(solution:\) 这道题很短,开门见山,很明显的告诉了读者这是一道多重背包.但是这道题的数据范围很不友好,它不允许我们直接将这一题当做01背包去做.于是我们得想一想优化. ...

  2. hdu 2844 poj 1742 Coins

    hdu 2844 poj 1742 Coins 题目相同,但是时限不同,原本上面的多重背包我初始化为0,f[0] = 1;用位或进行优化,f[i]=1表示可以兑成i,0表示不能. 在poj上运行时间正 ...

  3. 题解报告:hdu 2844 & poj 1742 Coins(多重部分和问题)

    Problem Description Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. On ...

  4. poj 1742 Coins(dp之多重背包+多次优化)

    Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar. ...

  5. POJ 1742 Coins(多重背包, 单调队列)

    Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar. ...

  6. [POJ 1742] Coins 【DP】

    题目链接:POJ - 1742 题目大意 现有 n 种不同的硬币,每种的面值为 Vi ,数量为 Ni ,问使用这些硬币共能凑出 [1,m] 范围内的多少种面值. 题目分析 使用一种 O(nm) 的 D ...

  7. POJ 1742 Coins 【多重背包DP】

    题意:有n种面额的硬币.面额.个数分别为A_i.C_i,求最多能搭配出几种不超过m的金额? 思路:dp[j]就是总数为j的价值是否已经有了这种方法,如果现在没有,那么我们就一个个硬币去尝试直到有,这种 ...

  8. POJ 1742 Coins(多重背包) DP

    参考:http://www.hankcs.com/program/cpp/poj-1742-coins.html 题意:给你n种面值的硬币,面值为a1...an,数量分别为c1...cn,求问,在这些 ...

  9. poj 1742 Coins (多重背包)

    http://poj.org/problem?id=1742 n个硬币,面值分别是A1...An,对应的数量分别是C1....Cn.用这些硬币组合起来能得到多少种面值不超过m的方案. 多重背包,不过这 ...

随机推荐

  1. Matlab 文件格式化/Matlab Source File Formattor

    由于需要使用到别人编写的Matlab代码文件,但是呢不同的人有不同的风格,有的写得就比较糟糕了. 为了更好地理解代码的内容,一个比较美观的代码会让人身心愉悦. 但是在网上并没有找到一个比较好的实现,此 ...

  2. html的标签规范

    if/else标签{ % if condition1 %} ... display 1{ % elif conditon2 %} ... display 2{ % else % } ... displ ...

  3. 20191118 Spring Boot官方文档学习(4.9)

    4.9.安全 如果Spring Security在类路径上,则默认情况下Web应用程序是采用的.Spring Boot依靠Spring Security的内容协商策略来确定使用httpBasic还是f ...

  4. SpringBoot 单元测试junit test

    pom引用 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http: ...

  5. [Web 前端] 023 js 的流程控制、循环和元素的获取、操作

    1. Javascript 流程控制 用于"基于不同条件执行不同的动作"的场合 1.1 if 语句 三种形式 // 第一种 if... // 第二种 if... else ... ...

  6. linux服务器上安装mysql

    mysql版本:mysql-5.6.44-linux-glibc2.12-x86_64.tar linux操作系统和版本信息: 1.检查linux服务器上是否已安全mysql [root@localh ...

  7. Spring框架 课程笔记

    Spring框架 课程笔记 第1章  Spring概述 1.1 Spring概述 1)        Spring是一个开源框架 2)        Spring为简化企业级开发而生,使用Spring ...

  8. The Frog's Games

    The Frog's Games Problem Description The annual Games in frogs' kingdom started again. The most famo ...

  9. python day1-requests

    一.什么是requests Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库. 相对于urllib库(自带,无需手动安装)而言, ...

  10. luogu P1232 [NOI2013]树的计数

    传送门 这题妙蛙 首先考虑构造出一个合法的树.先重新编号,把bfs序整成\(1,2,3...n\),然后bfs序就是按照从上到下从左往右的遍历顺序,所以可以考虑对bfs序分层,可以知道分层方式只会对应 ...