xynuoj 1426 逃亡的准备(多重背包或混合背包)

1426: 逃亡的准备

时间限制: 1 Sec  内存限制: 128 MB
提交: 13  解决: 7
您该题的状态:已完成
[提交][状态][讨论版]

题目描述

      每个人小时候都有自己的理想,但随着时间推移,渐渐的大多数人的理想变成了金钱.地位.面子... 于是大多数人 就变成了传说中的俗人。但我们的中中始终有自己的梦想,他要 环 游 世 界! 在20XX年X月X日中中开始环游世 界的准备工作.他开始准备自己的行囊
中中背包的容积为m ,中中有n样有用的东西 ,每样东西都有自己的价值Wi,和体积Vi ,每一样物品有Ni个 (Ni=0时表示有无限多个),于是乎我们的问题就是(你应该已经猜到了)...中中能带走的 东西的最大价值。
30%数据满足  1 <= m,n <=1000
100%数据满足  1 <=m,n <= 10000

输入

第 1 行: N,M--物品的种类和背包的容积 
第 2-N+1 行: Vi,Wi,Pi--三个整数:每个物品的体积.价值.个数

输出

单独的一行在给定的限制里可能得到的最大的价值。

样例输入

5 50 
1 1 50
2 4 3
48 49 1
1 51 1
3 3 3

样例输出

106

题中描述有ni=0时可以无线取,典型的混合背包,但是队友当时没注意,用了多重背包,由此可见,后台数据都没有ni=0的情况,完全背包不考虑也行。但是用普通的多重背包,队友好像时间超限了,混合背包模板在我别的博客也有,就不贴了。

多重背包优化做法:

//求指定体积V下的最大价值 
#include <iostream> 
#include<string.h>
#include<algorithm>
#include<stdio.h> 
using namespace std;
#define ll long long
int dp[10050];
int wi[10050];//价值 
int vi[10050];//体积 
int pi[10050];//个数
int Value[111110];
int size[111110];
int main()
{
    //count存储分解完后的物品总数  
    //Value存储分解完后每件物品的价值  
    //size存储分解完后每件物品的体积  
	int n,v;
	scanf("%d%d",&n,&v);
	int count=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&vi[i],&wi[i],&pi[i]);
		for(int j=1; j<=pi[i]; j<<=1)
        {
                //<<右移1位,相当于乘2  
            Value[count]=j*wi[i];  
            size[count++]=j*vi[i]; 
            pi[i]-=j;  
        }  
        if(pi[i]>0)  
        {  
            Value[count]=pi[i]*wi[i];  
            size[count++]=pi[i]*vi[i];  
        }
	} 
        //经过上面对每一种物品的分解,  
        //现在Value[]存的就是分解后的物品价值  
        //size[]存的就是分解后的物品体积  
        //count就相当于原来的 n
        //下面就直接用01背包算法来解  
        memset(dp,0,sizeof(dp));
        for(int i=0; i<count;i++)
            for(int j=v;j>=size[i];j--)
                if(dp[j]<dp[j-size[i]]+Value[i]) 
                    dp[j]=dp[j-size[i]]+Value[i]; 
  
        printf("%d\n",dp[v]);    
    return 0;
}  

---------更新----------

上面的多重背包做法,数组大小开的时候至少比题目要求大十倍,Value、size数组更要大很多,不然会超时,很难把握。今天做了一道HDU 2844多重背包,此模板时间也是快接近TEl了,主要是数组不好控制,发现了下面这个模板,数组按题意开,时间也比上个模板快。

//指定体积内的最大值 
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[100007],n,m,a[10005],b[10005],c[10005],count;
void zeropack(int cost,int value)
{//01背包选择 
    for(int i=m;i>=cost;i--)
        dp[i]=max(dp[i],dp[i-cost]+value);
}
void completepack(int cost,int value)
{//完全背包选择 
    for(int i=cost;i<=m;i++)
        dp[i]=max(dp[i],dp[i-cost]+value);
}
void multipack(int cost,int value,int num)
{//进行判断,const :体积;value:价值;num:个数 
    if(num*cost>=m)
    {
        completepack(cost,value);
        return;
    }
    int k=1;
    while(k<num)
    {
        zeropack(k*cost,k*value);
        num-=k;
        k*=2;
    }
    zeropack(num*cost,num*value);
}
int main()
{
    	scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i],&b[i],&c[i]);
        memset(dp,0,sizeof(dp));
        count=0;
        for(int i=1;i<=n;i++)
        {
            multipack(a[i],b[i],c[i]);
        }
        printf("%d\n",dp[m]);
    return 0;
}
                                                                                                                                                                    2018.05.12
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值