我是靠谱客的博主 完美板凳,最近开发中收集的这篇文章主要介绍hdu 3591 多重背包+完全背包练习题,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1 题目

http://acm.hdu.edu.cn/showproblem.php?pid=3591


题意:货币系统有 N 种不同面值的钱,每种钱的价值分别为 V1,V2,...,VN 一个人要买价值和为 T 的商品,他每种分别相应的带了 C1,C2,...,CN ,然后问你交易完成后所需要经手的钱币最少数目
思路:先对人进行多重背包,然后对售货员进行完全背包
答案其实和以前做的那题 背包超过容量的处理是一样的(uva 10819)
一直情况就是那个人所带的钱刚好凑成了 T ,那么就不需要找钱了,否则就需要找钱,相当于那个人支付了他所能付的超过 T 的钱 M,然后售货员找钱 M-T ,把这两者的经手的钱数加起来就行了
初始化的时候除了 dp[0]=0 之外,其它的都为 inf 表示 i 这个状态是可以由商品组合起来的
否则如果全部初始化为 0 的话,i 只能说是一个上界

1.2 题解

But Xiaoqian is a low-pitched girl , she wouldn’t like giving out more than 20000 once.一次不会付钱超过20000块。
背包容量是钱的价值,重量是钱的数目(每个钱币的重量都是1),求给出相同的钱的价值可以使用的最少(注意不是最大)的钱币数量。
动态规划求的是最小值。

对于主人公方用多重背包求,售后员方用完全背包求。 然后背包容量之差恰好等于T的情况中取使用硬币数目最少的。

      ans = INT_MAX;
        for(i=T;i<20001;i++)
            ans = min(ans,dp[i]+dp[i-T])

2 AC代码

2,.1 版本一(超时了)

#include<iostream>
#include<algorithm>
#include<limits.h>
using namespace std;
int inf = 20001; //足够大的数
int v = 20000; //背包的容量
//处理一件01背包中的物品
void ZeroOnePack(int dp[], int cost, int weight)
{
for (int i = v; i >= cost; i--)//descend
dp[i] = min(dp[i], dp[i - cost] + weight);
}
//deal with one item
void CompletePack(int dp[], int cost, int weight)
{
for (int i = cost; i <= v; i++)
dp[i] = min(dp[i], dp[i - cost] + weight);
}
//deal with one item
void MultiplePack(int dp[], int cost, int weight, int number)
{
if (cost*number >= v) //注意等于号
{
//物品足够多转化为完全背包
CompletePack(dp, cost, weight);
return;
}
int k = 1;
while (k < number)//二进制拆分
{
ZeroOnePack(dp, k*cost, k*weight);
number -= k;
k << 2;
}
ZeroOnePack(dp, cost*number, weight*number);
}
int main(int)
{
int dp[20002], dp2[20002];//背包容量是钱的价值,重量是钱的数目(每个钱币的重量都是1),求给出相同的钱的价值可以使用的最少(注意不是最大)的钱币数量
//But Xiaoqian is a low-pitched girl , she wouldn’t like giving out more than 20000 once.一次不会付钱超过20000块
int N, T, v[101], c[101], cnt = 0, i, j, ans;
while (scanf("%d %d", &N, &T) != EOF && (N != 0 || T != 0))
{
cnt++;
if (N == 0 || T == 0)
{
printf("Case %d: %dn", cnt, 0);
continue; //这里打成continue会卡在那里一直等待输入,报time limit exceeded
}
for (i = 1; i <= N; i++)
scanf("%d", &v[i]);
for (i = 1; i <= N; i++)
scanf("%d", &c[i]);
//初始化
for (i = 0; i<20002; i++)
dp[i] = inf, dp2[i] = inf;
//这里的初值只能设置为足够大,而不能是INT_MAX,否则dp[i - cost] + weight会由于溢出变成负数!!!
dp[0] = dp2[0] = 0; //注意dp[0]是有意义的,要单独初始化!!!
//背包
for (i = 1; i<=N; i++) //这里的上界应该是物品的数量
CompletePack(dp2, v[i], 1);
for (i = 1; i<=N; i++)//这里的上界应该是物品的数量
MultiplePack(dp, v[i], 1, c[i]);
ans = INT_MAX;
int t = inf;
for (i = T; i<20001; i++)
if (ans > dp[i] + dp2[i - T])
{
ans = dp[i] + dp2[i - T];
t = i;
}
!(dp[t] == inf || dp[t - T] == inf) ? printf("Case %d: %dn", cnt, ans) : printf("-1n");
}
return 0;
}
/**
3 70
5 25 50
5 2 1
0 0
**/


158936032015-12-18 14:19:58Time Limit Exceeded35911000MS1664K2186 BG++aaaaaaaaaaaaalc

说实话不明白这个代码为什么会超时,这个代码跟下面一个版本本质上是一样的。



2.2 版本二

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e2 + 10;//110
const int maxm = 2e4 + 10; //20010
const int INF = 1e8;
int c[maxn], v[maxn], f[maxm], g[maxm];
int main()
{
int n, m, tt = 0;
while (scanf("%d%d", &n, &m) != EOF)
{
if (n == 0 && m == 0)break;
int i, j, k;
for (i = 0; i<n; i++)
scanf("%d", &v[i]);
for (i = 0; i<n; i++)
scanf("%d", &c[i]);
for (i = 1; i <= 20000; i++)
{
g[i] = f[i] = INF;
}
f[0] = g[0] = 0;
//完全背包
for (i = 0; i<n; i++)
{
for (j = v[i]; j <= 20000; j++)
g[j] = min(g[j], g[j - v[i]] + 1);
}
//多重背包
for (i = 0; i<n; i++)
{
if (v[i] * c[i] >= 20000)
{
for (j = v[i]; j <= 20000; j++)
f[j] = min(f[j], f[j - v[i]] + 1);
continue;
}
for (k = 1; k<c[i]; k = k * 2)
{
for (j = 20000; j >= v[i] * k; j--)
f[j] = min(f[j], f[j - v[i] * k] + k);
c[i] -= k;
}
for (j = 20000; j >= c[i] * v[i]; j--)
f[j] = min(f[j], f[j - v[i] * c[i]] + c[i]);
}
int ans = INF;
for (i = m; i <= 20000; i++)
ans = min(ans, f[i] + g[i - m]);
if (ans == INF)ans = -1;
printf("Case %d: %dn", ++tt, ans);
}
return 0;
}
158930972015-12-18 13:14:08Accepted359146MS1716K1344 BG++aaaaaaaaaaaaalc


3 总结

     目前对dp[]数组初始化对程序的影响过程不算很清楚。

3.2  初始化问题

注意dp[0]是有意义的,要单独初始化!!!

dp[i] = inf, dp2[i] = inf;  //这里的初值只能设置为足够大,而不能是INT_MAX,否则dp[i - cost] + weight会由于溢出变成负数!!!



最后

以上就是完美板凳为你收集整理的hdu 3591 多重背包+完全背包练习题的全部内容,希望文章能够帮你解决hdu 3591 多重背包+完全背包练习题所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部