背包类问题

01背包(ZeroOnePack): 有N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。 完全背包(CompletePack): 有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 多重背包(MultiplePack): 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 比较三个题目,会发现不同点在于每种背包的数量,01背包是每种只有一件,完全背包是每种无限件,而多重背包是每种有限件。

模板:

c是重量,w是价值,n是个数

void bag01(int c,int w)
{
    for(int i=v; i>=c; i--)
        dp[i]=max(dp[i],dp[i-c]+w);
}
void bagall(int c,int w)
{
    for(int i=c; i<=v; i++)
        dp[i]=max(dp[i],dp[i-c]+w);
}
void multbag(int c,int w,int n)
{
    if(c*n>=v)
    {
        bagall(c,w);
        return;
    }
    int k=1;
    while(k<=n)
    {
        bag01(k*c,k*w);
        n-=k;
        k*=2;
    }
    bag01(n*c,n*w);
}

用法:

先循环每一件物品的各个属性,最后dp[v]的值就是答案

以多重背包为例

const int N=50000+10;
int dp[N],v;
int num[N],weight[N],value[N];
void bag01(int c,int w)
{
    for(int i=v; i>=c; i--)
        dp[i]=max(dp[i],dp[i-c]+w);
}
void bagall(int c,int w)
{
    for(int i=c; i<=v; i++)
        dp[i]=max(dp[i],dp[i-c]+w);
}
void multbag(int c,int w,int n)
{
    if(c*n>=v)
    {
        bagall(c,w);
        return;
    }
    int k=1;
    while(k<=n)
    {
        bag01(k*c,k*w);
        n-=k;
        k*=2;
    }
    bag01(n*c,n*w);
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&v);
    for(int i=1; i<=n; i++)
    {
        scanf("%d%d%d",&weight[i],&value[i],&num[i]);
    }
    for(int i=1; i<=n; i++)
        multbag(weight[i],value[i],num[i]);
    printf("%d\n",dp[v]);
    return 0;
}

zb的生日dp:

把一堆物品分成两堆,每个物品有自己的重量,最后使得两堆的差值最小.

//dp[v]:为其中一个人获得的重量,sum-dp[v]为另一个人重量,dp数组开的大一点
int sum = 0;
for (int i = 0; i < n; i++)
{
    scanf("%d", &a[i]);
    sum += a[i];
}
int v = sum / 2;
for (int i = 0; i < n; i++)
    for (int j = v; j >= a[i]; j--)
        dp[j] = max(dp[j], dp[j - a[i]] + a[i]);

results matching ""

    No results matching ""