动规专项——背包问题

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

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]) f[i][j]=max(f[i1][j],f[i1][jw[i]]+v[i])
由于状态 i i i 都是由状态 i − 1 i-1 i1 转化来的,所以可以将二维数组压缩为一维数组。

这个代码的状态 f [ i ] [ j ] f[i][j] f[i][j] 为在第 i i i个草药花费时间为 j 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] f[i][j] 为在第 i i i个草药花费时间恰好 j j j时的最大价值

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

  • 0
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:鲸 设计师:meimeiellie 返回首页
评论

打赏作者

華灯初上

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值