背包问题之完全背包---HDU(1114)

完全背包和01背包的的不同之处在于只要满足条件每一种物品都可拿无限次。dp[i][j]表示前i件物品中选若干物品放到空间为j的背包中的最大价值。状态转移方程:dp[0][j]=0;dp[i][j]=max(dp[i-1][j]]+k*w[i]+k*v[i]); 0<=k。如果按这样写下去,代码有三重循环,复杂度为O(nW^2),因此对其简化,简化后的代码为

for(int i=1;i<=n;i++)
{
    for(int j=1;j<=W;j++)
    {
       if(j<w[i])
            dp[i][j]=dp[i-1][j]; 
       else
        dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);//后边的为dp[i][j-w[i]]+v[i]
    }
}
printf("%d\n",dp[n][W]);

同样,也可以对代码降维:

for(int i=0;i<n;i++)
{
    for(int j=w[i];j<=W;j++)//与01背包只是顺序不同
    {
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    }
}
printf("%d\n",dp[W]);

可以发现,这两个代码和上篇01背包的代码特别相似,区别已在代码上标示。具体原因呢,特别复杂(我也不懂--_--||),若想深入了解可以去网上搜索背包问题九讲(Tianyi Cui),我感觉里面讲的很详细。

下面看一道例题:

Piggy-Bank--->http://acm.hdu.edu.cn/showproblem.php?pid=1114

在 ACM 能够开展之前,必须准备预算,并获得必要的财力支持。该活动的主要收入来自于 Irreversibly Bound Money (IBM)。思路很简单。任何时候,某位 ACM 会员有少量的钱时,他将所有的硬币投入到小猪储钱罐中。这个过程不可逆,因为只有把小猪储钱罐打碎才能取出硬币。在足够长的时间之后,小猪储钱罐中有了足够的现金,用于支付 ACM 活动所需的花费。

但是,小猪储钱罐存在一个大的问题,即无法确定其中有多少钱。因此,我们可能在打碎小猪储钱罐之后,发现里面的钱不够。显然,我们希望避免这种不愉快的情况。唯一的可能是,称一下小猪储钱罐的重量,并尝试猜测里面的有多少硬币。假定我们能够精确判断小猪储钱罐的重量,并且我们也知道给定币种的所有硬币的重量。那么,我们可以保证小猪储钱罐中最少有多少钱。

你的任务是找出最差的情形,即判断小猪储钱罐中的硬币最少有多少钱。我们需要你的帮助。不能再贸然打碎小猪储钱罐了!

输入

输入包含 T 组测试数据。输入文件的第一行,给出了 T 的值。

对于每组测试数据,第一行包含 E 和 F 两个整数,它们表示空的小猪储钱罐的重量,以及装有硬币的小猪储钱罐的重量。两个重量的计量单位都是 g (克)。小猪储钱罐的重量不会超过 10 kg (千克),即 1 <= E <= F <= 10000 。每组测试数据的第二行,有一个整数 N (1 <= N <= 500),提供了给定币种的不同硬币有多少种。接下来的 N 行,每行指定一种硬币类型,每行包含两个整数 P 和 W (1 <= P <= 50000,1 <= W <=10000)。P 是硬币的金额 (货币计量单位);W 是它的重量,以 g (克) 为计量单位。

输出

对于每组测试数据,打印一行输出。每行必须包含句子 “The minimum amount of money in the piggy-bank is X.” 其中,X 表示对于给定总重量的硬币,所能得到的最少金额。如果无法恰好得到给定的重量,则打印一行 “This is impossible.” 。

示例输入

3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4

示例输出

The minimum amount of money in the piggy-bank is 60.
The minimum amount of money in the piggy-bank is 100.
This is impossible.

分析:这个题就是完全背包问题的小变形,修改下模板,初始化dp数组(比较重要)应该就行了。

代码如下:

#include<iostream>
using namespace std;
int w[10005];
int v[10005];
int dp[10005];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int E,F;//E空,F装钱
        cin>>E>>F;
        int W=F-E;//硬币净重
        int N;
        cin>>N;
        for(int i=1;i<=W;i++) dp[i]=9999999;
        dp[0]=0;
        for(int i=1;i<=N;i++)
        {
            cin>>w[i]>>v[i];
        }
        for(int i=1;i<=N;i++)
        {
            for(int j=v[i];j<=W;j++)
            {
                dp[j]=min(dp[j],dp[j-v[i]]+w[i]);//此处根据题意改成min
            }
        }
        if(dp[W]==9999999) cout<<"This is impossible."<<endl;
        else cout<<"The minimum amount of money in the piggy-bank is "<<dp[W]<<"."<<endl;
    }
    return 0;
}

如有错误,还请大佬指出批评,O(∩_∩)O谢谢。

猜你喜欢

转载自blog.csdn.net/BestRivenW/article/details/81537993
今日推荐