背包问题

01背包问题

问题描述

有N件物品和一个容量为C的背包。第i件物品的体积是c[i],价值是v[i]。求解将哪些物品装入背包可使价值总和最大。

分析

动态规划算法,状态转移方程:
dp[i][j]=max{dp[i-1][j],dp[i-1][j-c[i]]+v[i]} 
其中,dp[i-1][j]表示第i件物品不装入背包中,而dp[i-1][j-c[i]]+v[i]表示第i件物品装入背包中。
时间复杂度为O(C*N) ,空间复杂度O(C*N)  。 时间复杂度已经无法优化,但是空间复杂度则可以优化为O(C),因为每次只是用到了上一步中的两个值, 将V(也就是j)递减的方式进行遍历,即V.......0 的方式进行即可节省空间,重复利用。

初始化

若要求背包必须放满,则初始如下:
        f[0] = 0 , f[1...V]表示-INF。表示当容积为0时,只接受一个容积为0的物品入包。
若要求背包可以空下,则初始化如下:
        f[0...V] = 0 ,表示任意容积的背包都有一个有效解即为0。    
具体解释如下:
     初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。
     如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,
     其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。
     如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,
     这个解的价值为0,所以初始时状态的值也就全部为0了。

代码

未对空间复杂度进行优化:
#include<iostream>
#include<cstdlib>
#include <cstring>
#define max(a,b) a>b?a:b
using namespace std;
int main()
{
    int C,N;//total cost,total num
    cin>>C>>N;
    int** dp=(int **)malloc((N+1)*sizeof(int *));
    dp[0]=(int *)malloc((C+1)*(N+1)*sizeof(int));
    for(int i=1;i<=N;i++)
        dp[i]=dp[i-1]+(C+1);
    //http://03071344.lofter.com/post/10871e_34cade
    int* c=(int *)malloc((N+1)*sizeof(int));//cost of each staff
    int* v=(int *)malloc((N+1)*sizeof(int));//value of each staff
    for(int i=1;i<=N;i++)
        cin>>c[i]>>v[i];
    memset(dp[0],0,sizeof(dp[0]));
    for(int i=1;i<=N;i++)//each staff
    {
        for(int j=0;j<=C;j++)//cost
        {
            if(j>=c[i])
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+v[i]);
            else
                dp[i][j]=dp[i-1][j];
            //show the dp table
            cout<<dp[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<dp[N][C]<<endl;


    free(v);
    free(c);
    free(dp[0]);
    free(dp);
    return 0;
}

进行空间复杂度优化:
#include<iostream>
#include<cstdlib>
#include <cstring>
#define max(a,b) a>b?a:b
using namespace std;
int main()
{
    int C,N;//total cost,total num
    cin>>C>>N;
    int* dp=(int *)malloc((C+1)*sizeof(int));
    int* c=(int *)malloc((N+1)*sizeof(int));//cost of each staff
    int* v=(int *)malloc((N+1)*sizeof(int));//value of each staff
    for(int i=1;i<=N;i++)
        cin>>c[i]>>v[i];
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=N;i++)//each staff
    {
        for(int j=C;j>=0;j--)//cost,from max to min
        {
            if(j>=c[i])
                dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
            //show the dp table in real order
            cout<<dp[C-j]<<" ";
        }
        cout<<endl;
    }
    cout<<dp[C]<<endl;


    free(v);
    free(c);
    free(dp);
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值