算法刷题-动态规划之背包问题

1.背包问题之01(4.30)

题目描述

小明有一个容量为 VV 的背包。

这天他去商场购物,商场一共有 NN 件物品,第 ii 件物品的体积为 wiwi​,价值为 vivi​。

小明想知道在购买的物品总体积不超过 VV 的情况下所能获得的最大价值为多少,请你帮他算算。

输入描述

输入第 11 行包含两个正整数 N,VN,V,表示商场物品的数量和小明的背包容量。

第 2∼N+12∼N+1 行包含 22 个正整数 w,vw,v,表示物品的体积和价值。

1≤N≤1021≤N≤102,1≤V≤1031≤V≤103,1≤wi,vi≤1031≤wi​,vi​≤103。

输出描述

输出一行整数表示小明所能获得的最大价值。

输入输出样例

输入5 20 1 6 2 5 3 8 5 15 3 3

输出 37

代码实例:

#include <iostream>

#include <algorithm>

using namespace std;

int dp[1001];

int main() {

int n,V;

cin>>n>>V;

for(int i=1;i<=n;i++){

int w,v;

cin>>w>>v;

for(int j=V;j>=w;j--){

dp[j]=max(dp[j],dp[j-w]+v);

}

}

cout<<dp[V]<<endl;

}

2.

问题描述

小秋家里来了 nn 位客人,编号为 1,2,3,…,n1,2,3,…,n 。现在小秋要给每一位客人倒水。

每个客人都有一个满意度,对于第 ii 个客人,满意度是这样定义的:

  • 如果小秋给第 ii 位客人倒了 aiai​ 毫升水,客人的满意度为 bibi​;
  • 如果小秋给第 ii 位客人倒了 cici​ (ci>ai)(ci​>ai​) 毫升水,客人的满意度为 didi​;
  • 如果小秋给第 ii 位客人倒的水不足 aiai​ 毫升(可以为 00),客人的满意度为 eiei​;
  • 如果客人满意度已经是 didi​,继续给该客人倒水不会改变客人的满意度。

现在小秋有 mm 毫升水,请问他要怎么样给客人倒水,才能让所有客人的满意度之和最大呢?你只需要求出所有客人满意度之和的最大值。

输入格式

第 11 行输入两个正整数 nn 和 mm,表示客人的数量和小秋拥有水的体积。

接下来 nn 行,每行五个整数 aiai​, bibi​, cici​, didi​, eiei​,第 ii 行表示给第 ii 位客人倒了 aiai​ 毫升水满意度为 bibi​,倒了 cici​ 毫升水满意度为 didi​,倒水不足 aiai​ 毫升满意度为 eiei​。

输出格式

输出仅一行,包含一个整数,表示所有客人满意度之和的最大值。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll dp[1005][1005];//dp[i][j]表示只考虑前i个客人,共倒水j毫升所得的最大好感度

int main(){

int n,m;

cin>>n>>m;

for(int i=1;i<=n;i++){

ll a,b,c,d,e;

cin>>a>>b>>c>>d>>e;

for(int j=0;j<=m;j++){

if(j<a)dp[i][j]=dp[i-1][j]+e;

else if(j>=a&&j<c)dp[i][j]=max(dp[i-1][j]+e,dp[i-1][j-a]+b);

else dp[i][j]=max(dp[i-1][j-a]+b,max(dp[i-1][j]+e,dp[i-1][j-c]+d));

}

}

cout<<dp[n][m]<<endl;

return 0;

}

3.

在一个探险者的团队中,小明和小红是合作的盗墓贼。

他们成功盗取了一座古墓中的宝藏,包括 nn 件不同重量的珍贵文物和黄金,第 ii 件宝藏的重量为 aiai​。

现在,他们希望公平地分配这些宝藏,使得小明所分得的宝藏的总重量等于小红所分得的宝藏的总重量。

请检查是否存在这样的分配方案,需要注意的是,宝藏不能被分割成两半来调整重量,只能整个宝藏进行分配。

输入格式

第一行包含一个正整数 nn,表示有 nn 件宝藏。

接下来 nn 行,第 ii 行表示第 ii 件宝藏的重量 aiai​。

输出格式

如果能公平分配输出 yesyes,否则输出 nono。

代码:

#include<bits/stdc++.h>

using namespace std;

const int N=2e4+3;

int dp[N];

int a[1005],sum;

int main(){

int n;cin>>n;

for(int i=1;i<=n;i++){

cin>>a[i];

sum+=a[i];

}

if(sum&1){

cout<<"no";

return 0;

}

sum/=2;

for(int i=1;i<=n;i++){

for(int j=sum;j>=a[i];j--){

dp[j]=max(dp[j],dp[j-a[i]]+a[i]);

}

}

cout<<(dp[sum]==sum?"yes":"no");

return 0;

}

三道题的解题思路:

1.第一题为最基础的01背包问题,为模版题。

2.第二题关键是dp数组的确定,以及根据题意,对于不同状态下动态转移的合理设置。

3.第三题巧用dp数组求解是否存在dp[sum/2]=sum/2的情况


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值