动规专项——背包问题

背包问题可以去看一下背包九讲

0-1背包

https://www.luogu.org/problemnew/show/P1048

记忆化搜索代码:

/**
* memory search
* P1048
* @author Hongchuan CAO
*/

#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cstdio>

using namespace std;

int val[110][2];
int mem[110][1010];

int t,m;
int result = 0;

void clear(){
    for(int i=0;i<110;i++){
        for(int j=0;j<1010;j++){
            mem[i][j] = -1;
        }
    }
}

void get_data(){
    scanf("%d%d",&t,&m);
    for(int i=0;i<m;i++){
        scanf("%d%d",&val[i][0],&val[i][1]);
    }
}

int dfs(int index,int lleft){
	//if searched, return directly
    if(mem[index][lleft]!=-1) return mem[index][lleft];
	//return 0 if index>=m
    if(index>=m) return 0;
    int chose=0,uchose=0;
	//divide into two condition (choose or not)
    uchose = dfs(index+1,lleft);
    if(lleft>=val[index][0]){
        chose = dfs(index+1,lleft-val[index][0])+val[index][1];
    } 
    //add to memory array
    return mem[index][lleft] = max(uchose,chose);
}

int main(){
    clear();
    get_data();
    printf("%d\n",dfs(0,t));
    return 0;
}

DP代码:
状态转移方程:
f [ i ] [ j ] = m a x ( f [ i 1 ] [ j ] , f [ i 1 ] [ j w [ i ] ] + v [ i ] ) f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i])
由于状态 i i 都是由状态 i 1 i-1 转化来的,所以可以将二维数组压缩为一维数组。

这个代码的状态 f [ i ] [ j ] f[i][j] 为在第 i i 个草药花费时间为 j j 时的最大价值(此时的时间花费或许并不等于j,应该是小于等于j)
所以在初始化的时候所有的值都为0

/**
 * DP : dp[j] = max(dp[j],dp[j-w[i]]+val[i]);
 * p1048
 * @author Hongchuan CAO
 */


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>

using namespace std;

const int INF = 1e8;
int t,m;
int dp[1010];
int stat[110][2];

//all inital is zero which is important

void get_data(){
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&stat[i][0],&stat[i][1]);
    }
}

void solve(){
    for(int i=1;i<=m;i++){
        for(int j=t;j>=stat[i][0];j--){
            dp[j] = max(dp[j],dp[j-stat[i][0]]+stat[i][1]);
        }
    }
    printf("%d\n",dp[t]);
}

int main(){
    get_data();
    solve();
    return 0;
}

还有一种做法为
状态 f [ i ] [ j ] f[i][j] 为在第 i i 个草药花费时间恰好 j j 时的最大价值

在初始化的时候只有dp[0][0]为0,其他的值都是负无穷 其实这个地方的负无穷是为了使那些不能恰好的点一直为负数,也可以进行特判,遇到这样的点可以直接跳过状态转移方程。
所以到最后,最终的结果并不是 d p [ n ] [ m ] dp[n][m] ,而是 d p [ n ] [ 0... m ] dp[n][0...m] 中的最大值。(因为其中所有的结果都是恰好填满时间的最大价值)

/**
 * DP : dp[j] = max(dp[j],dp[j-w[i]]+val[i]);
 * p1048
 * @author Hongchuan CAO
 */


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>

using namespace std;

const int INF = 1e8;
int t,m;
int dp[1010];
int stat[110][2];

void clear(){
    for(int i=1;i<1010;i++) dp[i] = -INF;
    dp[0] = 0;
}

void get_data(){
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&stat[i][0],&stat[i][1]);
    }
}

void solve(){
    int maxx = -1;
    for(int i=1;i<=m;i++){
        for(int j=t;j>=stat[i][0];j--){
            dp[j] = max(dp[j],dp[j-stat[i][0]]+stat[i][1]);
        }
    }

    for(int i=0;i<=t;i++){
        maxx = max(maxx,dp[i]);
    }
    printf("%d\n",maxx);
}

int main(){
    clear();
    get_data();
    solve();
    return 0;
}

完全背包

https://www.luogu.org/problemnew/show/P1616

多重背包

https://vjudge.net/problem/POJ-1742

猜你喜欢

转载自blog.csdn.net/baidu_41560343/article/details/92739976