多重背包

5 篇文章 0 订阅
1 篇文章 0 订阅
①基本题型:有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
②解题思路:将一种多件转化为多种一件。向01和完全背包转化。

1.

Description

急!灾区的食物依然短缺! 
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。 
请问:你用有限的资金最多能采购多少公斤粮食呢? 

后记: 
人生是一个充满了变数的生命过程,天灾、人祸、病痛是我们生命历程中不可预知的威胁。 
月有阴晴圆缺,人有旦夕祸福,未来对于我们而言是一个未知数。那么,我们要做的就应该是珍惜现在,感恩生活―― 
感谢父母,他们给予我们生命,抚养我们成人; 
感谢老师,他们授给我们知识,教我们做人 
感谢朋友,他们让我们感受到世界的温暖; 
感谢对手,他们令我们不断进取、努力。 
同样,我们也要感谢痛苦与艰辛带给我们的财富~ 


 

Input

输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
 

Output

对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
 

Sample Input

     
     
1 8 2 2 100 4 4 100 2
 

Sample Output

     
     
400
 


c++,dp,多重背包

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
#define maxn 105

int n,m,t;
int p[maxn],h[maxn],c[maxn],dp[maxn];

//完全背包
void CompletePack(int cost, int weight)
{
    for (int i = cost; i <= n; i++)
        dp[i]=max(dp[i], dp[i - cost] + weight);
}

//01背包
void ZeroOnePack(int cost, int weight)
{
    for (int i = n; i >= cost; i--)
      dp[i]=max(dp[i], dp[i - cost] + weight);
}

//多重背包
void MultiplePack(int cost, int weight, int number)
{
    //如果大于等于金额,就按完全背包处理(此时相当于不限定袋数)
    if (cost * number >= n) { CompletePack(cost, weight); return; }
    int k = 1;
    while (k < number)
    {
        ZeroOnePack(k * cost, k * weight);
        number -= k; k *= 2;
    }
    ZeroOnePack(number * cost, number * weight);
}



void solve()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++)
		scanf("%d%d%d",&p[i],&h[i],&c[i]);
		memset(dp,0,sizeof(dp));
		for (int i = 0; i < m; i++) MultiplePack(p[i], h[i], c[i]);
    printf("%d\n", dp[n]);
}

int main()
{
	scanf("%d",&t);
	while(t--) solve();
	return 0;
}



2.多重背包记录路径



多重背包记录方案
Time Limit:1000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u

Description

Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he often buys coffee at coffee vending machines at motorests. Charlie hates change. That is basically the setup of your next task. 

Your program will be given numbers and types of coins Charlie has and the coffee price. The coffee vending machines accept coins of values 1, 5, 10, and 25 cents. The program should output which coins Charlie has to use paying the coffee so that he uses as many coins as possible. Because Charlie really does not want any change back he wants to pay the price exactly. 

Input

Each line of the input contains five integer numbers separated by a single space describing one situation to solve. The first integer on the line P, 1 <= P <= 10 000, is the coffee price in cents. Next four integers, C1, C2, C3, C4, 0 <= Ci <= 10 000, are the numbers of cents, nickels (5 cents), dimes (10 cents), and quarters (25 cents) in Charlie's valet. The last line of the input contains five zeros and no output should be generated for it.

Output

For each situation, your program should output one line containing the string "Throw in T1 cents, T2 nickels, T3 dimes, and T4 quarters.", where T1, T2, T3, T4 are the numbers of coins of appropriate values Charlie should use to pay the coffee while using as many coins as possible. In the case Charlie does not possess enough change to pay the price of the coffee exactly, your program should output "Charlie cannot buy coffee.".

Sample Input

12 5 3 1 2
16 0 0 0 1
0 0 0 0 0

Sample Output

Throw in 2 cents, 2 nickels, 0 dimes, and 0 quarters.
Charlie cannot buy coffee.


题意大概是说一个人要用不同的有限的硬币买咖啡,请问他要付不同的硬币个多少?抽象为背包就是一定必须把背包填满,而且物品数量有限。




c++.背包.多重背包记录方案

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

const int INF  = 100000;
const int MaxM = 10005;
const int MaxN = 105;
int n, dp[MaxM], ans[MaxN];
int path[MaxM], used[MaxM];
int num[4], val[4] = {1, 5, 10, 25};

void solve()
{
    for (int i = 0; i < 4; i++) scanf("%d", &num[i]);
    fill(dp + 1, dp + MaxM, -INF); dp[0] = 0;
    memset(path, 0, sizeof(path)); path[0] = -1;
    for (int i = 0; i < 4; i++)
    {
        memset(used, 0, sizeof(used));
        for (int j = val[i]; j <= n; j++)
		{
            if (dp[j-val[i]] != -INF && dp[j] < dp[j - val[i]] + 1
                && used[j - val[i]] + 1 <= num[i]) {
                dp[j] = dp[j - val[i]] + 1;
                used[j] = used[j - val[i]] + 1;
                path[j] = j - val[i];
            }
        }
    }
    memset(ans, 0, sizeof(ans));
    if (dp[n] == -INF) puts("Charlie cannot buy coffee.");
    else
    {
        while (path[n] != -1)
        {
            ans[n - path[n]]++;
            n = path[n];
        }
        printf("Throw in %d cents, %d nickels, ", ans[val[0]], ans[val[1]]);
        printf("%d dimes, and %d quarters.\n", ans[val[2]], ans[val[3]]);
    }
}

int main()
{
    while(~scanf("%d",&n)&&n)
        solve();
       return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值