算法分析与设计实验:01背包

问题描述:

有N件物品和一个容量为V的背包。第i件物品的重量是weight[i],价值是value[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。注意,与背包问题不同的是,每件物品只有整个装入和不装入两个选项,且每件物品只能装入一次。

算法描述:

使用f(i,v)表示将前i个物品选择性装入剩余容量为v的背包时能得到的最大价值。这里我们把第i件物品和前i-1件物品分开来看,第i件物品只有装和不装两种选择。

1.如果不装的话剩余容量不减少,价值也不变,因此在这种情况下f(i,v)=f(i-1,v)

2.如果装的话则容量减少,价值增加,因此在这种情况下f(i,v)=f(i-1,v-weight[i])+value[i]

从自顶向下的视角看,如果装了第i个物品的话在下一层就要求解前i-1件物品在剩余容量减少的情况下的最大价值,如果没有装则要求解前i-1件物品在剩余容量不变的情况下的最大价值。

因此对于第i件物品的装和不装问题我们只要取两者的最大值就可以了。所以可以得到状态转移方程:

f(i,v)=f(i-1,v)                                           (v<weight[i],即剩余容量不足,不能放入物品)

f(i,v)=f(i-1,v-weight[i])+value[i]                (v>=weight[i],即剩余容量充足)

由于每一行数据仅取决于上一行,所以可使用滚动数组进行优化

代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//f[i][v]=max{ f[i-1][v],f[i-1][v-w[i]]+val[i] }
//f[v]=max(f[v-weight[i]]+value[i],f[v])
int solve(int n,int capacity,vector<int> &weight,vector<int> &value)
{
    if(n<0||capacity<=0)
        return 0;
    vector<int> f(capacity+1);
    for(int i=0;i<n;i++)
    {
        for(int v=capacity;v>0;v--)
        {
            if(v>=weight[i]) f[v]=max(f[v-weight[i]]+value[i],f[v]);
        }
    }
    return f[capacity];
}

int main()
{
    int n,capacity;
    cin>>n>>capacity;
    vector<int> weight(n);
    vector<int> value(n);
    for(int i=0;i<n;i++)
    {
        cin>>weight[i]>>value[i];
    }

    int ans=solve(n,capacity,weight,value);
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/misaka-cn-cs/p/12743480.html