动态规划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\n", 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.\n");
        else
            printf("The minimum amount of money in the piggy-bank is %d.\n", 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\n", 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\n", ans);
    }
    return 0;
}

  

 

posted @ 2021-06-08 17:31  anyiya  阅读(35)  评论(0编辑  收藏  举报