背包问题

acm入门算法--简单背包问题


01背包问题
问题描述:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。


0-1背包问题


Time Limit: 1 Second(s)    Memory Limit: 32 MB
Total Submission(s): 1172   Accepted Submission(s): 456

Problem Description
 
给定n种物品和1个背包,物品i的重量是wi,其价值为vi,背包的容量为C。要求选择装入背包的物品,使得装入背包中物品的总价值最大。

Input

每组测试数据包含3行,第1行为n和c,表示有n(0<=n<=400)个物品且背包容量为c (c<=1500),第二行为这n个物品的重量wi(1<=wi<=1000),第三行为这n个物品的价值vi。背包容量和物品重量都为整数。

Output

输出装入背包的最大总价值,每个答案一行。

Sample Input

5 10
2 2 6 5 4
6 3 5 4 6

Sample Output

15

算法思想:背包问题是典型的动态规划问题,给定一个背包和这个背包的承重量,怎么放才能使背包实现物品的最大价值。

01背包问题的特点是:每种物品仅有一件,可以选择放或不放。(所以说是最基础的,后面还会有完全背包,多重背包,就不局限在一件,也可以有更多选择)。

接下来我们来确认状态转移方程:

每一件物品都有两种选择,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果第i件物品重量不超过背包的承重量(超重肯定不能放),

我们选择不把第i件物品放入背包中,此时背包实现的最大价值就等同于前i-1件物品在同等容量背包中实现的最大价值f[i-1][c];

如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为c-w[i]的背包中”,此时能获得的最大价值就是f [i-1][c-w[i]]再加上通过放入第i件物品获得的价值v[i]。

设f[i][j]为第i件物品放入背包容量为j的背包中实现的最大价值,不难得出状态转移方程为:

f[i][j]=max{f[i-1][c], f[i-1][c-w[i]]+v[i]}

下面贴出代码:

 #include<iostream.h>
#include<string.h>
int f[402][1502],w[402],v[402];

int max(int a,int b)
{
    return a>b?a:b;
}

int KnapSack(int n,int c,int w[],int v[])
{
    int i,j;
    memset(f,0,sizeof(f));
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=c;j++)
        {
            if(j<w[i-1])//物品重量超过背包容量
                f[i][j]=f[i-1][j];
            else//选择放或不放的最优策略
                f[i][j]=max(f[i-1][j],f[i-1][j-w[i-1]]+v[i-1]);
        }
    }
    return f[n][c];
}

int main()
{
    int n,c;
    while(cin>>n>>c)
    {
        int i;
        for(i=0;i<n;i++) cin>>w[i];
        for(i=0;i<n;i++) cin>>v[i];
        int maxv=KnapSack(n,c,w,v);
        cout<<maxv<<endl;
    }

    return 0;
}

 二维背包问题

问题描述:大体与01背包相似,只是多了个限制条件,01背包会了,这个也不难

二维费用背包问题

Time Limit: 1 Second(s)    Memory Limit: 32 MB
Total Submission(s): 91   Accepted Submission(s): 49

Problem Description
 
给定N种物品和1个背包,物品i的体积是ai,重量是bi, 价值为vi,背包的体积为V,背包的最大承载重量W。要求选择装入背包的物品,使得装入背包中物品的总价值最大。

Input

每组测试数据包含4行,第1行为N,V,W,表示有N个物品且背包体积为V和载重量W,第2行为这N个物品的体积ai,第3行为这N个物品的重量bi,第4行为这N个物品的价值vi。

所有输入数字都为整数,范围大于0,小于等于100。处理到文件结束。

Output

输出装入背包的最大总价值,每个答案一行。

Sample Input

4 3 1
1 1 1 2
2 2 1 1
3 3 1 3

Sample Output

3

算法思想:状态转移方程同01背包类似,多了体积这个限制,如果第i件物品放入背包中问题就转化为“前i-1件物品放入剩下的承重量为c-w[i],体积为v-a[i]的背包”,

此时能获得的最大价值就是f [i-1][c-w[i]][v-a[i]]再加上通过放入第i件物品获得的价值v[i]。

设f[i][j][k]为第i件物品放入背包容量为j,体积为k的背包中实现的最大价值,不难得出状态转移方程为:

f[i][j][k]=max{f[i-1][c][v], f[i-1][c-w[i]][v-a[i]]+v[i]}

代码如下:

#include<iostream>
#include<string>
using namespace std;
int a[100],v[100],w[100],f[100][100][100];
 
int maxV(int v1,int v2){
    return v1>v2?v1:v2;
}
 
int main(){
    int N,V,W;
    while(cin>>N>>V>>W){
         
     
    int i,j,k;
    memset(f,0,sizeof(f));
    for(i=0;i<N;i++)cin>>a[i];
    for(i=0;i<N;i++)cin>>w[i];
    for(i=0;i<N;i++)cin>>v[i];
    for(i=0;i<N;i++){
        for(j=0;j<=V;j++){
            for(k=0;k<=W;k++){
                if(i==0){//第一件物品
                    if(a[i]<=j&&w[i]<=k)//满足背包条件限制
                        f[i][j][k]=v[i];//最大实现价值为当前物品价值
                }
                else{
                     
                    if(a[i]>j||w[i]>k)
                        f[i][j][k]=f[i-1][j][k];
                    else
                        f[i][j][k]=maxV(f[i-1][j][k],f[i-1][j-a[i]][k-w[i]]+v[i]);
                }
            }
        }
    }
 
     
    cout<<f[N-1][V][W]<<endl;
    }
    return 0;
}

 

 

 

 

posted on 2017-04-26 21:31  栖木  阅读(209)  评论(0编辑  收藏  举报

导航