zoukankan      html  css  js  c++  java
  • 背包问题小总结

    背包问题我现在初学几个简单的,一个是01背包,一个是完全背包,还有一个是多重背包。

    他们三者可以相互转化,主要基础就是01背包和完全背包。

    具体内容可以去看背包九讲。

    给几个例题:

    A - Piggy-Bank

    这个是一个裸的01背包

    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #define inf64 0x3f3f3f3f3f3f3f3f
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn = 1e5 + 10;
    int dp[maxn];
    int c[maxn], val[maxn];
    int main()
    {
        int t;
        scanf("%d", &t);
        while(t--)
        {
            int w1, w2;
            scanf("%d%d", &w1, &w2);
            int w = w2 - w1;
            int n;
            scanf("%d", &n);
            memset(dp, inf, sizeof(dp));
            dp[0] = 0;
            for (int i = 1; i <= n; i++) scanf("%d%d", &val[i], &c[i]);
            for(int i=1;i<=n;i++)
            {
                for(int j=c[i];j<=w;j++)
                {
                    dp[j] = min(dp[j], dp[j - c[i]]+val[i]);
                }
            }
            if (dp[w] >= inf) printf("This is impossible.
    ");
            else printf("The minimum amount of money in the piggy-bank is %d.
    ", dp[w]);
        }
        return 0;
    }
    01背包

    I - Coins

     这个是一个裸的多重背包

    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #define inf64 0x3f3f3f3f3f3f3f3f
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn = 1e6 + 10;
    int num[maxn], dp[maxn], val[maxn];
    int N,V;
    
    void zero(int weight,int value)
    {
        for(int i=V;i>=weight;i--)
        {
            dp[i] = max(dp[i], dp[i - weight] + value);
        }
    }
    
    void all(int weight,int value)
    {
        for(int i=weight;i<=V;i++)
        {
            dp[i] = max(dp[i], dp[i - weight] + value);
        }
    }
    
    void solve()
    {
        int t = 1;
        int ncount = 0;
        for(int i=1;i<=N;i++)
        {
            if (num[i] * val[i] >= V) all(val[i], val[i]);
            else
            {
                t = 1;
                ncount = num[i];
                while(t<=ncount)
                {
                    zero(t*val[i], t*val[i]);
                    ncount -= t;
                    t *= 2;
                }
                zero(ncount*val[i], ncount*val[i]);
            }
        }
    }
    
    int main()
    {
        while(cin>>N>>V&&N!=0&&V!=0)
        {
            for (int i = 1; i <= N; i++) scanf("%d", &val[i]);
            for (int i = 1; i <= N; i++) scanf("%d", &num[i]);
            memset(dp, -inf, sizeof(dp));
            dp[0] = 0;
            solve();
            int ans = 0;
            for(int i=1;i<=V;i++)
            {
                if (dp[i] > 0) ans++;
                //printf("dp[%d]=%d
    ",i, dp[i]);
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    多重背包

    C - Dollar Dayz

     这个是一个裸的01背包,不过这个有一点点不一样,这个dp记录的是方案数。

    这个还要注意,因为这个和顺序无关,只要你把东西放入背包,所以这个时候枚举的顺序要注意

    先枚举容量,再枚举物品;如果和顺序有关就要先枚举物品再枚举容量。

    这个题目要先枚举容量。

    除此之外还要注意这个会爆long long

    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn = 1e4 + 10;
    typedef long long ll;
    const ll inf64 = 1000000000000000000;
    ll a[maxn], b[maxn];
    
    int main()
    {
        int n, k;
        while(scanf("%d%d", &n, &k)!=EOF)
        {
            memset(a, 0, sizeof(a));
            memset(b, 0, sizeof(b));
            b[0] = 1;
            for(int i=1;i<=k;i++)
            {
                for(int j=i;j<=n;j++)
                {
                    a[j] = a[j] + a[j - i] + (b[j] + b[j - i]) / inf64;
                    b[j] = (b[j] + b[j - i]) % inf64;
                }
            }
            if (a[n] == 0) printf("%lld
    ", b[n]);
            else printf("%lld%018lld
    ", a[n], b[n]);
        }
        return 0;
    }
    大数+背包

    E - Charlie's Change

     这个是一个01背包+输出路径,这个路径的输出可以看背包九讲。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn = 1e5 + 10;
    
    int dp[maxn], used[maxn], path[maxn];
    int weight[4] = { 1,5,10,25 };
    
    int main()
    {
        int n, num[5];
        while(scanf("%d%d%d%d%d",&n,&num[0],&num[1],&num[2],&num[3])!=EOF)
        {
            if (n == 0 && num[0] == 0 && num[1] == 0 && num[2] == 0 && num[3] == 0) break;
            memset(dp, -inf, sizeof(dp));
            memset(path, 0, sizeof(path));
            dp[0] = 0;
            path[0] = -1;
            for(int i=0;i<4;i++)
            {
                memset(used, 0, sizeof(used));
                for(int j=weight[i];j<=n;j++)
                {
                    if(dp[j-weight[i]]+1>dp[j]&&dp[j-weight[i]]>=0&&used[j-weight[i]]<num[i])
                    {
                        dp[j] = dp[j - weight[i]] + 1;
                        path[j] = j - weight[i];
                        used[j] = used[j - weight[i]] + 1;
                    }
                }
            }
            if (dp[n] < 0) printf("Charlie cannot buy coffee.
    ");
            else
            {
                int ans[100];
                memset(ans, 0, sizeof(ans));
                while(path[n]!=-1)
                {
                    ans[n - path[n]]++;
                    n = path[n];
                }
                printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.
    ", ans[weight[0]], ans[weight[1]], ans[weight[2]], ans[weight[3]]);
            }
        }
        return 0;
    }
    01背包+输出路径

    F - The Fewest Coins

     这个是一个多重背包和完全背包的混合,需要进行一定的转化

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn = 2e5 + 10;
    int N, V;
    int weight[maxn], num[maxn];
    int f1[maxn], f2[maxn], V1;
    void zeroonepack(int weight, int val, int f[]) {
        for (int i = V; i >= weight; i--) {
            f[i] = min(f[i], f[i - weight] + val);
        }
    }
    
    void completepack(int weight, int val, int f[]) {
        for (int i = weight; i <= V; i++) {
            f[i] = min(f[i], f[i - weight] + val);
        }
    }
    
    void multiplepack(int weight, int val, int count, int f[]) {
        if (count*weight >= V) completepack(weight, val, f);
        else {
            int t = 1;
            while (t < count) {
                zeroonepack(weight*t, val*t, f);
                count -= t;
                t *= 2;
            }
            zeroonepack(count*weight, count*val, f);
        }
    }
    
    int main() {
        while (scanf("%d%d", &N, &V1) != EOF) {
            int max_val = 0;
            for (int i = 1; i <= N; i++) {
                scanf("%d", &weight[i]);
                max_val = max(max_val, weight[i]);
            }
            for (int i = 1; i <= N; i++) scanf("%d", &num[i]);
            V = max_val * max_val + V1 + 10;
            memset(f1, inf, sizeof(f1));
            memset(f2, inf, sizeof(f2));
            f1[0] = 0, f2[0] = 0;
            for (int i = 1; i <= N; i++) {
                multiplepack(weight[i], 1, num[i], f1);//顾客
            }
            for (int i = 1; i <= N; i++) {
                completepack(weight[i], 1, f2);
            }
            //printf("v=%d v1=%d
    ", V, V1);
            int ans = inf;
            for (int i = 0; i <= V - V1; i++) {
                if (f1[V1 + i] != inf && f2[i] != inf) {
                    ans = min(f1[V1 + i] + f2[i], ans);
                }
            }
            if (ans != inf) printf("%d
    ", ans);
            else printf("-1
    ");
        }
        return 0;
    }
    完全背包+多重背包
  • 相关阅读:
    C语言小项目-基于TCP协议和SOCKET编程的网络通信系统
    c语言小项目-使用mysql数据库的图书管理系统
    常用功能函数-密码登陆函数
    C++小项目-吃豆子游戏
    C语言小项目-火车票订票系统
    使用单向链表保存大量数据的基础程序框架
    Oracle创建用户并赋予权限
    Fibonacci sequence 求余数
    sizeof运算符来获取各种数据类型在内存中所占字节数--gyy整理
    C++不同进制整数
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/10929400.html
Copyright © 2011-2022 走看看