• 动态规划4.4——背包问题


    题目上添加了超链接,大家点一下题目就会自动跳转到Poj原题界面~~              冲鸭冲鸭ヾ(◍°∇°◍)ノ゙。

    前言:

    建议大家按随笔顺序阅览,背包问题是一类很经典的动态规划问题,知识涵盖可以占常见动态规划类型里的10%。

    由于前辈们总结的太好,现在基本上见不到单纯的模板背包问题了,命题人多会结合一些其他知识点进行综合考察,当然背包问题本身就涉及了许多不同的算法。之前有用心写过一篇关于背包问题的随笔,(点我)这里就直接给大家送上链接了。想要大家看一下(羞赧)。

    动态规划组成部分:

    1:确定状态

          —确定最后一步(最优策略)

          —抽象子问题

    2:归纳转移方程

    3:初始条件和边界情况

    4:计算顺序

     

    4.4.1 Charm Bracelet (3624)

    题意:n个物品,每个物品有w和d属性,要求选出一定的物品,在Σw不超过m的情况下,使得Σd最大。

    小笔记:01背包问题

    #include <cstdio>
    using namespace std;
    #define MAX(a, b) (a > b ? a : b)
    int F[15000], V;
    //0-1背包,其中c为费用,w为价值,V为最大容量
    void zeroonePack(int c, int w)
    {
        for (int v = V; v >= c; v--)
            F[v] = MAX(F[v], F[v - c] + w);
    }
    int main()
    {
        int n;
        scanf("%d%d", &n, &V);
        while (n--)
        {
            int w, d;
            scanf("%d%d", &w, &d);
            zeroonePack(w, d); //本题中对应的费用为w,价值为d
        }
        printf("%d
    ", F[V]);
        return 0;
    }
    

      

    4.4.2 Piggy-Bank (1384)

    题意:n种不同的硬币,有两个属性,p代表价值,w代表重量,钱罐空时重e,满时重f,计算满时钱罐里最小可能的价值是多少。

    小笔记:完全背包问题

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    int V, F[10001];
    //完全背包,其中c为费用,w为价值,V为最大容量
    void completePack(int c, int w)
    {
        for (int v = c; v <= V; v++)
            F[v] = min(F[v], F[v - c] + w);
    }
    int main()
    {
        int t;
        scanf("%d", &t);
        while (t--)
        {
            int e, f, n;
            scanf("%d%d%d ", &e, &f, &n);
            scanf("");
            V = f - e;
            fill(F + 1, F + V + 1, INF);
            while (n--)
            {
                int p, w;
                scanf("%d%d", &p, &w);
                completePack(w, p); //本题中对应的费用为w,价值为p
            }
            if (F[V] == INF)
                printf("This is impossible.
    ");
            else
                printf("The minimum amount of money in the piggy-bank is %d.
    ", F[V]);
        }
        return 0;
    }
    

      

    4.4.3 Cash Machine (1276)

    题意:有n台提款机,每台提款机提供货币的不同的面值和数量,求这些机器能提取的不超过指定限额的最大金额。

    小笔记:多重背包问题

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 100001;
    int V; //指定限额的最大金额
    int F[N];
    void zeroonePack(int c, int w)
    {
        for (int v = V; v >= c; v--)
            F[v] = max(F[v], F[v - c] + w);
    }
    void completePack(int c, int w)
    {
        for (int v = c; v <= V; v++)
            F[v] = max(F[v], F[v - c] + w);
    }
    //多重背包,其中c为费用,w为价值,m为数量
    void multiplePack(int c, int w, int m)
    {
        if (c * m >= V)
        {
            completePack(c, w);
            return;
        }
        int k = 1;
        while (k < m)
        {
            zeroonePack(k * c, k * w);
            m -= k;
            k <<= 1;
        }
        zeroonePack(m * c, m * w);
    }
    int main()
    {
        int n;
        while (~scanf("%d%d", &V, &n))
        {
            fill(F, F + N, 0);
            while (n--)
            {
                int m, d;
                scanf("%d%d", &m, &d);
                multiplePack(d, d, m); //本题中费用和价值都是d,对应数量为m
            }
            printf("%d
    ", F[V]);
        }
        return 0;
    }
    

      

    4.4.4 Coins (1742)

    题意:有n种硬币,每种硬币具有不同的面值和个数,问可以组成1…m中多少个面值。

    小笔记:多重背包问题

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 100001;
    int V, F[N];
    void zeroonePack(int c, int w)
    {
        for (int v = V; v >= c; v--)
            if (F[v] < F[v - c] + w)
                F[v] = F[v - c] + w;
    }
    void completePack(int c, int w)
    {
        for (int v = c; v <= V; v++)
            if (F[v] < F[v - c] + w)
                F[v] = F[v - c] + w;
    }
    void multiplePack(int c, int w, int m)
    {
        if (c * m >= V)
        {
            completePack(c, w);
            return;
        }
        int k = 1;
        while (k < m)
        {
            zeroonePack(k * c, k * w);
            m -= k;
            k <<= 1;
        }
        zeroonePack(m * c, m * w);
    }
    int main()
    {
        int n;
        while (scanf("%d%d", &n, &V) && (n || V))
        {
            fill(F, F + N, 0);
            F[0] = 1;
            int a[101], c[101];
            for (int i = 0; i < n; i++)
                scanf("%d", &a[i]);
            for (int i = 0; i < n; i++)
                scanf("%d", &c[i]);
            for (int i = 0; i < n; i++)
                multiplePack(a[i], 0, c[i]); //本题费用对应a,数量对应c,因为只涉及面值,不涉及每种硬币的价值,所以不考虑w
            int ans = 0;
            for (int i = 1; i <= V; i++)
                if (F[i])
                    ans++;
            printf("%d
    ", ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    elastic
    Leetcode题库 第十行
    Leetcode题库-实现strStr()
    Redis持久化
    Redis的数据结构及应用场景
    Redis缓存的淘汰策略
    Redis缓存常见问题
    Redis面试题1
    消息队列的原理及选型
    【转载】java高并发/mysql/mybatis/spring博客
  • 原文地址:https://www.cnblogs.com/thx2199/p/15116738.html
Copyright © 2020-2023  润新知