一个不错的《背包九讲》的赏析博客。https://blog.csdn.net/yandaoqiusheng/article/details/84782655#commentBox
HihoCoder - 1038
https://vjudge.net/problem/HihoCoder-1038
且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了!
小Ho现在手上有M张奖券,而奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要need(i)张奖券进行兑换,同时也只能兑换一次,为了使得辛苦得到的奖券不白白浪费,小Ho给每件奖品都评了分,其中第i件奖品的评分值为value(i),表示他对这件奖品的喜好值。现在他想知道,凭借他手上的这些奖券,可以换到哪些奖品,使得这些奖品的喜好值之和能够最大。
抽象:
背包容量 m 1e5
石头个数 n 500
石头的重量为 need(i) 2e5
价值为 value(i) 1e3
设dp[i][j]表示第i个石头(前i个石头)、背包空间剩余j时可达到的最大收益。
有方程:
dp[i,j]= max( 放:dp[i-1,j-w[i]] + v[i] (条件为wi<=j),
不放:dp[i-1,j]
);
1<=i<=n
1<=j<=m
观察方程,与i无关,且每个方程需要得知对应j较小的答案。故空间优化:
dp[j]= max( 放:dp[j-w[i]] + v[i] (条件为wi<=j),
不放:dp[j]
);
1<=i<=n
m>=j>=1 (倒序)
#include
#include
using namespace std;
int const maxn=1e5+10;
#define max(i,j) ((i)>(j)?(i):(j))
int v[maxn];
int w[maxn];
int d[maxn];
/*
背包容量 m 1e5
石头个数 n 500
石头的重量为 need(i) 2e5
价值为 value(i) 1e3
*/
int main(int argc, const char * argv[]) {
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%d%d",w+i,v+i);
}
for(int i=1;i<=n;i++){
for(int j=m;j>=1 && w[i]<=j;j--){
d[j]=max(d[j-w[i]]+v[i],d[j]);
}
}
cout<
HDU - 2191
急!灾区的食物依然短缺!
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?
混合背包(多重背包问题),可直接转化为01背包问题,(也可用二进制优化)。
当然,还有O(vn)的方法,需要用到单调队列。具体见背包九讲。此处不列举了。
#include
#include
#include
using namespace std;
int const maxn=1e5+10;
#define max(i,j) ((i)>(j)?(i):(j))
int v[maxn];
int w[maxn];
int dp[200];
int c[maxn];
/*
背包容量 n 100
种类个数 m 100
石头个数cnt 2000
重量w 20 价值v 200 个数c 20
*/
int cnt;
inline void func(int x,int y,int z){
int wei=1;
while(z){
if(wei>z){
wei=z;
}
w[++cnt]=wei*x;
v[cnt]=wei*y;
z-=wei;
wei=wei<<1;
}
}
int main(int argc, const char * argv[]) {
int n,m;
int T;
cin>>T;
int x,y,z;
while(T--){
cnt=0;
cin>>n>>m;
memset(dp, 0,sizeof(dp));
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
func(x,y,z);
}
for(int i=1;i<=cnt;i++){
for(int j=n;j>=1 && j>=w[i];j--){
dp[j]=max(dp[j-w[i]]+v[i],dp[j]);
}
}
cout<
有n种不同种类的硬币,每种都有无限个。每种硬币的价值不同,重量不同。现在你有一个袋子最多可装m的重量,求在满足重量要求的情况下得到的最大价值是多少。
完全背包问题。相比于01背包比较“取”和“不取”,完全背包需要比较"取多少",所以需要多一层循环。
设重量为wi ,价值为vi
基本方程为:
定义:dp[i,j]表示前i种硬币、袋子剩余容量为j时,可以得到的最大价值。
方程:
dp[i,j]=max( dp[i-1,j-k*w[i]]+v[i]*k ) , 0<=k
1<=i<=n
1<=j<=m
空间压缩后:
dp[j]=max( dp[j-k*w[i]]+v[i]*k ) , 0<=k
1<=i<=n
m>=j>=w[i]
//
// main.cpp
// test
//
// Created by dawn on 2019/8/26.
// Copyright © 2019 chuyi. All rights reserved.
//
#include
#include
#include
using namespace std;
int const maxn=1e5+10;
#define max(i,j) ((i)>(j)?(i):(j))
int v[maxn];
int w[maxn];
int dp[maxn];
/*
总容量 m 石头种类数n
价值v
重量w
*/
int main(int argc, const char * argv[]) {
int n,m;
cin>>n>>m;
memset(dp, 0,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%d%d",w+i,v+i);
}
for(int i=1;i<=n;i++){
for(int j=m;j>=w[i];j--){
int max_k = j/w[i];
for(int k=0;k<=max_k;k++){
dp[j]=max(
dp[j],
dp[j-k*w[i]]+v[i]*k
);
}
}
}
cout<