背包

01背包

最大价值

背包数量为 \(V\),有 \(n\)件物品,重量为 \(w_i\),价值为 \(c_i\)。求能获得最大价值。

ll V, n, w[10000], c[10000], f[10000];

int main()
{
    V = read();
    n = read();
    for (int i = 1; i <= n; ++i)
    {
        w[i] = read();
        c[i] = read();
    }
    for (int i = 1; i <= n; ++i)
        for (int v = V; v >= w[i]; --v)
        {
            if (f[v - w[i]] + c[i] > f[v])
                f[v] = f[v - w[i]] + c[i];
        }
    printf("%lld\n", f[V]);
    return 0;
}

方案数

一种物品只能选一次,组合出固定价值的方案数问题。

例题:ybt1291:数字组合

ll a[21], f[1003], n, t;
int main()
{
    n = read();
    t = read();
    for (int i = 1; i <= n; ++i)
    {
        a[i] = read();
    }
    f[0] = 1;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = t; j >= a[i]; --j)
        {
            f[j] += f[j - a[i]];
        }
    }
    printf("%lld\n", f[t]);
    return 0;
}

完全背包

最大价值

一种物品可以选无限次。
只需要改一下第二层循环的循环顺序就行了。

for (int i = 1; i <= n; ++i)
    for (int v = w[i]; v <= V; ++v)
    {
        if (f[v - w[i]] + c[i] > f[v])
            f[v] = f[v - w[i]] + c[i];
    }

方案数

一种物品可以选无限次,组合出固定价值的方案数问题。
例题:ybt1293:买书

ll a[5], f[10002], m;

int main()
{
    m = read();
    a[1] = 10, a[2] = 20, a[3] = 50, a[4] = 100;
    f[0] = 1;
    for (int i = 1; i <= 4; ++i)
    {
        for (int j = a[i]; j <= m; ++j)
        {
            f[j] += f[j - a[i]];
        }
    }
    printf("%lld\n", f[m]);
    return 0;
}

混合背包

一种物品可以选 \(p\) 次。

ll w[31], c[31], p[31];
ll f[201], n, m;

int main()
{
    m = read();
    n = read();
    for (int i = 1; i <= n; ++i)
    {
        w[i] = read();
        c[i] = read();
        p[i] = read();
    }
    for (int i = 1; i <= n; ++i)
    {
        if (p[i] == 0) //完全
        {
            for (int j = w[i]; j <= m; ++j)
                f[j] = max(f[j], f[j - w[i]] + c[i]);
        }
        else //01和多重
        {
            for (int j = 1; j <= p[i]; ++j)
            {
                for (int k = m; k >= w[i]; --k)
                {
                    f[k] = max(f[k], f[k - w[i]] + c[i]);
                }
            }
        }
    }
    printf("%lld\n", f[m]);
    return 0;
}

二维费用背包

再加一重循环,多开一维数组即可。

例题:ybt1271:【例9.15】潜水员

ll v, u, k;
ll a[1091], b[1021], c[1092];
ll f[101][101];

int main()
{
    memset(f, 127, sizeof f);
    f[0][0] = 0;
    v = read();
    u = read();
    k = read();
    for (int i = 1; i <= k; ++i)
    {
        a[i] = read();
        b[i] = read();
        c[i] = read();
    }
    for (int i = 1; i <= k; ++i)
    {
        for (int j = v; j >= 0; --j)
        {
            for (int l = u; l >= 0; --l)
            {
                ll t1 = j + a[i];
                ll t2 = l + b[i];
                t1 = min(t1, v);
                t2 = min(t2, u);
                f[t1][t2] = min(f[t1][t2], f[j][l] + c[i]);
            }
        }
    }
    printf("%lld\n", f[v][u]);
    return 0;
}
原文地址:https://www.cnblogs.com/EdisonBa/p/14948724.html