• 【DP】01背包


    (精选上好代码讲解产自原装进口白皮书)

    01背包问题

    有n个重量和价值分别为wi,vi的物品,从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。

    首先我们用朴素的方式搜索一遍:

    int rec(int i,int j){
        int res;
        if(i==n)  res=0;//已经没有剩余物品了
        else if(j<w[i]) res=rec(i+1,j);//无法挑选这个物品
        else res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);//挑选和不挑选两种情况都尝试一下
        return res;
    }
    /*搜索深度为n 时间O(2^n)*/

    优化一下(记忆数组)

    int dp[maxn][maxn];
    int rec(int i,int j){
        if(dp[i][j]>0) return d[i][j];//已经计算过的话直接使用之前的结果
        int res;
        if(i==n) res=0;
        else if(j<w[i]) res=rec(i+1,j);
        else res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
        return dp[i][i]=res;//结果记录在数组中
    }

    不用递归函数,直接利用递推式:

    int dp[maxn][maxn];
    void fun()
    {
        for(int i = n - 1; i >= 0; i--)
        {
            for (int j = 0; j <= w; j++)
            {
                if(j < w[i])
                {
                    dp[i][j] = dp[i + 1][j];
                }
                else
                {
                    dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i]);
                }
            }
        }
        cout<<dp[0][w]<<endl;
    }

    以上DP都是关于i的逆向进行的循环

    那么正向定义如下:

    if (j<w[i])
        f[i][j] = f[i-1][j] 
    else
        f[i][j] = max(f[i-1][j], f[i-1][j-w[i]] + v[i])

    举个例子

    (w,v)//w是重量,v是价值

    (2,3)

    (1,2)

    (3,4)

    (2,2)

    ij

    0

    1

    2

    3

    4

    5

    0

    0

    0

    0

    0

    0

    0

    1

    0

    0

    3

    3

    3

    3

    2

    0

    2

    3

    5

    5

    5

    3

    0

    2

    3

    5

    6

    -

    如图所示,求dp[3][4]=max(dp[2][4],dp[2][1]+4)

     

     

     

    有关01背包的练手题~

    HDOJ 1159

    题意:求最长公共子序列

    思路:01背包模板

    #include<stdio.h>
    #include<string.h>
    #define MAX(a,b) (a>b?a:b)
    const int MAXN=1010;
    int dp[MAXN][MAXN];
    char a[MAXN],b[MAXN];
    int main(){
    while(~scanf("%s%s",a+1,b+1)){
        memset(dp,0,sizeof(dp));
        int i,j;
        for( i=1;a[i];i++){
            for(j=1;b[j];j++){
                if(a[i]==b[j])dp[i][j]=dp[i-1][j-1]+1;
                else dp[i][j]=MAX(dp[i][j-1],dp[i-1][j]);
            }
        }
        printf("%d
    ",dp[i-1][j-1]);
    }
    return 0;}
  • 相关阅读:
    C语言程序设计II—第六周教学
    第一次结对编程情况反馈
    C语言程序设计II—第五周教学
    C语言程序设计II—第四周教学
    放缩
    切线垂直
    指数为对数时取对数
    整体运算
    数列求通项+离散数列单调性判断
    整体运算+求零点
  • 原文地址:https://www.cnblogs.com/Kohinur/p/9028289.html
Copyright © 2020-2023  润新知