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的情况