背包问题

一,01背包
问题描述:有n个物体,它们有各自的重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
思路:定义f[i][j]表示当前背包容量为j,前i个物品最佳组合对应的价值,v[i]为物品的价值,w[i]为物品的重量,n为物品数量,c为背包容量,有下面两种情况
(1)j<w[i] f[i][j]=f[i-1][j]
(2)j>w[i] f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i])

在void find_max(){
int i,j;
for(i=1;i<=n;i++){
   for(j=1;j<=c;j++){
       if(j<w[i]){
       f[i][j]=f[i-1][j];//物品装不进去
        }
 		else{
	f[i][j]=max([f[i-1][j],f[i-1][j-w[i]]+v[i]);
        }
  }
}

代码优化:f[i][j]的转移只与f[i][x]有关,f[i][x]是由前一次循环得到,所以可将f压缩成一维数组,f[j]表示容量为j时的最大价值,所以f[j]=max(f[j],f[j-w[i]]+v[i]),c的循环应从答到小,以免本次f[j]的值被本次更新的f[j-w[i])影响

在这里void find_max_better(){
    int i,j;
    for(i=1;i<=n;i++){
	for(j=c;j>=w[i];j--){
	    if(f[j]<=f[j-w[i]]+v[i]){
		f[j]=f[j-w[i]]+v[i];
	    }
	 }
     }
    }

二,完全背包
完全背包问题是指每种物品都有无限件

void complete(){
	for(int i=1;i<=n;i++){
		for(int j=w[i];j<=c;j++){
			f[j]=max(f[i],f[j-w[i]]+value[i]);
		}
	}
} 

三,多重背包
多重背包限定的每种物品的数量,例如给有价值为2数量为10的物品,我们可以把10拆开,拆成以二进制表示的数,二进制可以表示任何数。所以10就可以有1,2,4,8之内的数表示,一开始选1,然后让10-1=9,再选2,9-2=7,再选4,7-4=3,因为3<8,所以10由1,2,4,3组成,求解方式可由01背包和完全背包组合,因为当数据大于背包容量时是可以任意取的,所以看作完全背包

在#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 1000         //物品个数 
#define M 100000000    //所有物品可能的最大价值 
int m[N],c[N],w[N],f[M];
int V;
int max(int a,int b){return a>b?a:b;}
void ZeroOnePack(int cost,int weight)
{
    int v;
    for(v=V;v>=cost;v--) f[v]=max(f[v],f[v-cost]+weight);
}
void CompletePack(int cost,int weight)
{
    int v;
    for(v=cost;v<=V;v++)
        f[v]=max(f[v],f[v-cost]+weight);
}
void MultiplePack(int cost,int weight,int amount)
{
    int k;
    if(cost*amount>=V)
    {
        CompletePack(cost,weight);
        return;
    }
    k=1;
    while(k<amount)
    {
        ZeroOnePack(k*cost,k*weight);
        amount=amount-k;
        k=k*2;
    }
    ZeroOnePack(amount*cost,amount*weight);
}
int main()
{
    int n,i;
    scanf("%d %d",&n,&V);
                                                   // 两种不同的初始化方式,根据情况自行选择 
    //memset(f,0,sizeof(f[0])*(V+1));              // 只希望价格尽量大 
    //memset(f,-M,sizeof(f[0])*(V+1));f[0]=0;      // 要求恰好装满背包 
    for(i=0;i<n;i++) scanf("%d %d %d",m+i,c+i,w+i);
    for(i=0;i<n;i++) MultiplePack(c[i],w[i],m[i]);
    printf("%d\n",f[V]);
    system("PAUSE");
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值