DP经典问题---背包问题的代码实现(入门级)(C++/PYTHON)

背包的状态转换方程

i:表示物品序号

j:表示背包大小

W [i]:表示第i件物品的重量

f[i,j]:表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值

f[i-1,j-Wi]:表示在前i-1件物品中选择若干件放在承重为j-Wi的背包中,可以取得的最大价值

Pi(j>=Wi):表示第i件物品的价值,要求背包大小j要大于此件物品的重量

f[i-1,j]:表示前i-1件物品中选择若干件放在承重为j的背包中,可以取得的最大价值

1.01背包问题2. 01背包问题 - AcWing题库

首先我们创立两个一维数组,用来存储大小和价值

再创立一个二维数组用来状态分析

分析背包问题我们是曲线救国,调用已经存在的数据元素来解决问题

物品个数是从1到n,然后分别得出该个数下的最大价值

我们要分析两个状态,放与不放,

第一种--不放i物品:f[i][j]=f[i-1][j](调用的是i-1状态下的最大值)

第二种--放i物品:f[i][j]=f[i-1] [j-v[i]] + w[i](此时同时是调用i-1个物品下的状态,

但是此时放物品那你要留空给这个物品放,so,此时调用的状态转移方程容量是j-v[i]条件下的,

最后再加上w[i]就是该状态下的value了)(当然,背包的容量要大于v[i]要不然放不下i 物品)

last but not least,我们要对两种状态,放与不放的价值大小进行判断

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

最后输出则可。

#include <bits/stdc++.h>
using namespace std;

const int N=1010;
int main(){
    int n,m;
    int v[N],w[N];
    int f[N][N];

    cin>>n>>m;
    for (int i=1;i<=n;i++) cin>>v[i]>>w[i];

    for (int i=1;i<=n;i++)//物品个数 1-n
        for (int j=0;j<=m;j++){//容量  0-m
            f[i][j]=f[i-1][j];//先赋值给不放第i个,在下面再比较放与不妨
            if (j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);//f[i][j]=  (1) f[i-1][j] (2) f[i-1][j-v[i]]+w[i]
            //第一种情况是取的是i-1个物品的最大 容量为j
            //第二种是[i-1]个但是把第i个放入的情况,那要取的是【i-1】,但是其内存要是j-v[i]--相当于留了一个地方存这个物品,取得是之前的最后再加上w[i]成为新的f[i][j]
        }
    cout<<f[n][m]<<endl;
    return 0;
}
n,m=map(int,input().split())#n是物品,m是容量
v=[]#容量
w=[]#价值
v.append(0)
w.append(0)
f=[[0 for j in range(n+m)] for i in range(m+n)]
for i in range(n):
    a,b=map(int,input().split())
    v.append(a)
    w.append(b)
for i in range(1,n+1):
    for j in range(0,m+1):
        f[i][j]=f[i-1][j]
        if j>=v[i]:
            f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i])
print(f[n][m])

2.完全背包问题3. 完全背包问题 - AcWing题库

#include <bits/stdc++.h>
using namespace std;

const int N=1010;

int v[N],w[N];
int f[N][N];
int n,m;
int main()
{
    cin>>n>>m;
    for (int i=1;i<=n;i++) cin>>v[i]>>w[i];
    for (int i=1;i<=n;i++)
        for (int j=0;j<=m;j++)
            for (int k=0;k*v[i]<=j;k++)
                f[i][j] = max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
    cout<<f[n][m]<<endl;
    return 0;
}
n, m = map(int, input().split())
v, w = [0] * (n + 1), [0] * (n + 1)

for i in range(1, n + 1):
    v[i], w[i] = map(int, input().split())

# 二维:
# 状态表示f[i][j] 选择前i个物品,总体积小于等于j的最大价值
# 状态计算f[i][j] = max(f[i-1][j], f[i][j - v[i] + w[i] if j >= v[i])
# 物品种类不限,所以max中第二项和0-1背包不同

f = [[0] * (m + 1) for _ in range(n + 1)]

for i in range(1, n + 1):
    for j in range(m + 1):
        f[i][j] = f[i-1][j]
        if j >= v[i]:
            f[i][j] = max(f[i][j], f[i][j-v[i]] + w[i])

print(max(f[n]))
n, m = map(int, input().split())
v, w = [0] * (n + 1), [0] * (n + 1)

for i in range(1, n + 1):
    v[i], w[i] = map(int, input().split())
# 一维:f[j] 代表总体积小于等于j的最大价值
# 因为每种物品数量不限,所以j从小到大更新,即可以使用前面当前层j更新后的结果

f = [0] * (m + 1)
for i in range(1, n + 1):
    for j in range(v[i], m + 1):
        f[j] = max(f[j], f[j-v[i]] + w[i])
print(f[m])

3.多重背包问题4. 多重背包问题 I - AcWing题库

#include <bits/stdc++.h>

using namespace std;

const int N=110;
int v[N],w[N],s[N];
int f[N][N];

int main()
{
    int n,m;
    cin>>n>>m;
    for (int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];
    for (int i=1;i<=n;i++)
        for (int j=0;j<=m;j++){
            for(int k=0;k<=s[i] && k*v[i]<=j;k++)
            {
                f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+w[i]*k);
            }
        }
    cout<<f[n][m]<<endl;
    return 0;
}
​
n,v = map(int, input().split())
goods = []
for i in range(n):
    goods.append([int(i) for i in input().split()])

new_goods = []

for i in range(n):
    for j in range(goods[i][2]):
        new_goods.append(goods[i][0:2])

goods = new_goods
n = len(goods)

dp = [0 for i in range(v+1)]

for i in range(n):
    for j in range(v,-1,-1):
        if j>= goods[i][0]:
            dp[j] = max(dp[j], dp[j - goods[i][0]] + goods[i][1])

print(dp[-1])

​

4.数字三角形3304. 数字三角形 - AcWing题库

数字三角形属于线性DP问题。状态表示也是一个2维数组,f[i][j],i,j分别表示行与列

状态分析同时也是f[i][j]调用已经存在的状态值,该题的f[i][j]可以由两个方向过来,左上右上,

左上:f[i-1][j-1]+a[i][j]

右上:f[i-1][j]+a[i][j]

f [i][j]=max ( f [i-1] [j-1] + a[i] [j] , f [i-1] [j] + a[i] [j])

数字三角形题目还需注意左右次数的问题。

#include<iostream>

using namespace std;

const int N = 510 , M = -1e9;;

int n;

int a[N][N];
int f[N][N];

int main(){
    cin >> n;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= i; j++){
            cin >> a[i][j];
        }
    }
    for(int i = 0; i <= n; i++){
        for(int j = 0; j <= i+1; j++){            
        //注意这里的循环判断条件 从零开始到最后一个数字的后一个位置都要初始化,因为他会用到左边界和右边界上的值.
            f[i][j] = M;
        }
    }
    f[1][1] = a[1][1];

    for(int i = 2; i <= n; i++){
    //前面第一个位置只有一种情况,所以从2开始
        for(int j = 1; j <= i; j++){
            f[i][j] = max(f[i-1][j-1]+a[i][j], f[i-1][j]+a[i][j]);
        }
    }
    if (n % 2 == 0) cout << max(f[n][n / 2], f[n][n / 2 + 1]) << '\n';
    else cout << f[n][n / 2 + 1];
    return 0;
}

n=int(input())
arrs=[[0 for i in range(1,n+1+1)] for i in range(n+1)]#存数的数组
arr=[[0 for i in range(1,n+3)] for i in range(n+1)]#动态规划状态调用数组
for i in range(1,n+1):
        arrs[i][1:n]=list(map(int,input().split()))
arr[1][1] =arrs[1][1]
for i in range(2,n+1):
    for j in range(1,i+1):
        arr[i][j]=max(arr[i-1][j-1]+arrs[i][j],arr[i-1][j]+arrs[i][j])

if n % 2 == 1:
    print(arr[-1][n//2 + 1])
else:
    print(max(arr[-1][n//2],arr[-1][n//2+1]))

注:作者一些题目的解法可能并不是最优解,可以就行指出探讨。

  • 50
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值