• 01背包 裸题两题


    第一题是poj的3624 这题限制了空间,所以我也不知道我的二维的写的是不是一定是对的。

    Bessie has gone to the mall's jewelry store and spies a charm bracelet. Of course, she'd like to fill it with the best charms possible from the N (1 ≤ N ≤ 3,402) available charms. Each charm i in the supplied list has a weight Wi (1 ≤ Wi ≤ 400), a 'desirability' factor Di (1 ≤ Di ≤ 100), and can be used at most once. Bessie can only support a charm bracelet whose weight is no more than M (1 ≤ M ≤ 12,880).

    Given that weight limit as a constraint and a list of the charms with their weights and desirability rating, deduce the maximum possible sum of ratings.

    Input

    * Line 1: Two space-separated integers: N and M
    * Lines 2..N+1: Line i+1 describes charm i with two space-separated integers: Wi and Di

    Output

    * Line 1: A single integer that is the greatest sum of charm desirabilities that can be achieved given the weight constraints

    Sample Input

    4 6
    1 4
    2 6
    3 12
    2 7

    Sample Output

    23


    这题用二维做会MLE,它的意思就是要你用一维去做,不过我把二维一维的都写上来

    一维
    #include<queue>
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N 1234567
    #define M 12
    
    int f[N];
    int w[N];
    int d[N];
    int n,m;
    int main()
    {
        while(~scanf("%d %d",&n,&m))
        {
            for(int i=1;i<=n;i++)
                scanf("%d%d",&w[i],&d[i]);
            memset(f,0,sizeof(f));
            for(int j=1;j<=n;j++)
            {
                for(int i=m;i>=0;i--)
                {
                    if(i>=w[j])
                        f[i]=max(f[i],f[i-w[j]]+d[j]);
                }
    
            }
            cout<<f[m]<<endl;
        }
        return 0;
    }
    /*
    4 6
    1 4
    2 6
    3 12
    2 7
    */

    二维

    #include<queue>
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N 12888
    #define M 12
    
    int f[N];
    int g[4000][N];
    int w[N];
    int d[N];
    int n,m;
    int main()
    {
        while(~scanf("%d %d",&n,&m))
        {
            for(int i=1;i<=n;i++)
                scanf("%d%d",&w[i],&d[i]);
            memset(g,0,sizeof(g));
            for(int i=1;i<=n;i++)
            {
                for(int v=m;v>=0;v--)
                {
                    g[i][v]=g[i-1][v];//开始就是少了这一句老是不对
                    if(v>=w[i])
                    g[i][v]=max(g[i-1][v],g[i-1][v-w[i]]+d[i]);
                }
            }
            cout<<g[n][m]<<endl;
        }
        return 0;
    }
    /*
    4 6
    1 4
    2 6
    3 12
    2 7
    */

    第二题是hdu 2602 这题空间没有限制,用一维二维均可,也就验证了我的二维的做法的正确性,

    #include<queue>
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N 1005
    #define M 2005
    
    int f[N][N];
    int w[N];
    int d[N];
    int n,V;
    int main()
    {
        int T;cin>>T;
        while(T--)
        {
            scanf("%d%d",&n,&V);
            for(int i=1;i<=n;i++)
                scanf("%d",&d[i]);
            for(int i=1;i<=n;i++)
                scanf("%d",&w[i]);
            memset(f,0,sizeof(f));
            for(int i=1;i<=n;i++)
                for(int v=V;v>=0;v--)
            {
                f[i][v]=f[i-1][v];
                if(v>=w[i])
                f[i][v]=max(f[i-1][v],f[i-1][v-w[i]]+d[i]);
            }
            cout<<f[n][V]<<endl;
    
    
        }
        return 0;
    }
    /*
    1
    5 10
    1 2 3 4 5
    5 4 3 2 1
    */

    其实第二层循环从0到V也是可以的,因为是二维的所以顺序不重要。

    但是注意不能写成

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

    或者

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

    因为这样有些发f[i][v]就没有从上一层的f[i-1][v]中得到,导致最后的结果不正确,但是一维的就可以这么写。

    到这里还没有结束,一维的可以这么写,但是一维的顺序不能颠倒,如果是01背包只能是从V递减,因为这样才能保证每件物品只取一次。如果是从0递增到V,(或者从w[i]递增到V),后面的大的v就可能由本层循环的前面得到的f[i][v]来推出,就不满足从上一层推出的意思了(实际上就是每种物品可能用不只1次)。 而这恰好是完全背包的概念。所以如果顺序是0到V(w[i]到V)的话其实就是完全背包的一种写法。

    DP真是神奇

  • 相关阅读:
    data guard switchover切换异常
    oracle dataguard
    建立信任关系
    sqlplus 打印很乱,而且很短就换行
    老友记英语
    每天读一遍
    extern的用法
    linux信号处理
    http server v0.1_http_parse.c
    http server v0.1_http_webapp.c
  • 原文地址:https://www.cnblogs.com/wmxl/p/4743825.html
Copyright © 2020-2023  润新知