背包问题可以去看一下背包九讲
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[i−1][j],f[i−1][j−w[i]]+v[i])
由于状态
i
i
i 都是由状态
i
−
1
i-1
i−1 转化来的,所以可以将二维数组压缩为一维数组。
这个代码的状态
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