[Sicily Coins] 动态规划 多重背包问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Xiao13Yu14/article/details/68941394

1. 问题描述

Description

Ouyang has 6 kinds of coins.
The number of the i-th coin is A[i] (0<=i<6).
Their value and weight are as follewed:
0. $0.01, 3g
1. $0.05, 5g
2. $0.10, 2g
3. $0.25, 6g
4. $0.50, 11g
5. $1, 8g
Ouyang want to run away from home with his coins.
But he is so weak that he can only carry M gram of coins.
Given the number of each coin he has, what is the maximal value of coins he can take?

Input

There are multiple cases.
Each case has one line with 7 integers: M (1<=M<=10000), A[i], (0<=i<6, 0<=A[i]<=100000).

Output

The maximal value of coins he can take.

Sample Input

1 1 1 1 1 1 1
38 3 1 10 4 2 1
75 8 5 23 4 2 4

Sample Output

$0.00
$2.40
$6.10

2. 基本思路

回顾:0-1背包问题

  • 在0-1背包问题中,给定n个物品,第i个物品有重量w[i]和价值v[i],用容量为W的背包来装物品,总价值最大是多少?
  • OPT(i, w)表示:背包容量为w时,考虑给定第1, 2, …, i个物品,能取得的最大价值。装物品的时候有以下两种情况:第一种情况是不选择第i个物品,那么最大价值将会是:容量为w,考虑物品{1, 2, …, i-1}所取得的价值;第二种情况是选择第i个物品,那么最大价值将会是:容量为(w-w[i]),考虑物品{1, 2, …, i-1}所取得的价值加上当前第i个物品的价值v[i]。
  • 0-1背包问题的代码实现如下 :
for (int w = 0; w <= W; w++)
{
    M[0, w] = 0;
}
for (int i = 1; i <= n; i++)
{
    for (w = 1; w <= W; w++)
    {
        if (wt[i] > w)
        {
            M[i, w] = M[i - 1, w];
        }
        else
        {
            M[i, w] = max(M[i - 1][w], v[i] + M[i - 1, w - wt[i]]);
        }
    }
}

多重背包问题

  • 以上的Coins问题属于多重背包问题。多重背包问题与0-1背包问题的不同之处在于:多重背包问题每种类型的物品可以有多个。
  • 在0-1背包的基础上加入以下内容即可实现:
M[i][w] = 0;
int nCount = min(A[i], w / wt[i]);
for(int k = 0; k <= nCount; k++)
{
    M[i][w] = max(M[i][w], k * value[i] + M[i - 1][w - k * wt[i]]);
}
  • nCount记录的是当前的第i种物品最多可以放多少个,受两个因素限制,第一个因素是一共有A[i]个类型i的物品,第二个因素是背包容量为w,最多能装(w / wt[i])个,取这两个数中较小的一个作为nCount。
  • 接着尝试放0到nCount个类型i的物品到背包。k等于多少就等于放多少个类型i的物品进去。
  • M[i][w]取的是M[i][w]和(k * value[i] + M[i - 1][w - k * wt[i]])中的最大值,这样才能更新M[i][w]。
  • 对于固定的i和w,M[i][w]并不是随着k的增大而增大的,有时候你可以选择不装这么多类型i的物品,留些容量装前面类型的物品,可能会使得总价值更大。

3. 代码实现

#include<iostream>
#include<iomanip> 
using namespace std;
int A[7];
double value[7] = {0, 0.01, 0.05, 0.10, 0.25, 0.50, 1.0};
int wt[7] = {0, 3, 5, 2, 6, 11, 8};
double M[10][11000] = {0};
int main()
{
    int W;
    while(cin >> W)
    {
        A[0] = 0;
        for(int i = 1; i <= 6; i++)
            cin >> A[i];
        for(int w = 0; w <= W; w++)
            M[0][w] = 0;
        for(int i = 0; i <= 6; i++)
            M[i][0] = 0;
        for(int i = 1; i <= 6; i++)
        {   
            for(int w = 1; w <= W; w++)
            {
                M[i][w] = 0;
                int nCount = min(A[i], w / wt[i]);
                for(int k = 0; k <= nCount; k++)
                {
                    M[i][w] = max(M[i][w], k * value[i] + M[i - 1][w - k * wt[i]]); //注意这里是取的是M[i][w]和(k * value[i] + M[i - 1][w - k * wt[i]])中的最大值,而不是M[i - 1][w]和(k * value[i] + M[i - 1][w - k * wt[i]])中的最大值。
                }
            }
        } 
        cout << "$" << fixed << setprecision(2) << M[6][W] << endl;
    }
    return 0;
}                                 
展开阅读全文

没有更多推荐了,返回首页