DP总结
1. 背包DP
-0/1背包
-完全背包
-多重背包
-分组背包
-依赖背包
-二维背包
-树形背包DP
0/1背包
朴素版
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
//f[i][j]表示前i个物品,体积不超过j时的最大价值
//不选第i个物品时,f[i][j] = f[i-1][j]
//选第i个物品时,f[i][j] = f[i-1][j-v[i]]+w[i],保证j>=v[i]
int f[maxn][maxn] = {}; //默认全为0,这样后面就不需要再初始化
int n = 0, m = 0; //n件物品,m为背包总容量
int v[maxn] = {}, w[maxn] = {}; //v表示第i件物品体积,w为第i件物品价值
int main()
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) scanf("%d%d", &v[i], &w[i]);
for(int i=1; i<=n; i++)
{
for(int j=0; j<=m; j++)
{
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]);
}
}
printf("%d", f[n][m]);
return 0;
}
滚动数组版
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int f[2][maxn] = {}; //默认全为0,这样后面就不需要再初始化
int n = 0, m = 0; //n件物品,m为背包总容量
int v[maxn] = {}, w[maxn] = {}; //v表示第i件物品体积,w为第i件物品价值
int main()
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) scanf("%d%d", &v[i], &w[i]);
for(int i=1; i<=n; i++)
{
for(int j=0; j<=m; j++)
{
f[i&1][j] = f[(i-1)&1][j];
if(j>=v[i]) f[i&1][j] = max(f[i&1][j], f[(i-1)&1][j-v[i]] + w[i]);
}
}
printf("%d", f[n&1][m]);
return 0;
一维
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int f[maxn] = {}; //默认全为0,这样后面就不需要再初始化
int n = 0, m = 0; //n件物品,m为背包总容量
int v[maxn] = {}, w[maxn] = {}; //v表示第i件物品体积,w为第i件物品价值
int main()
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) scanf("%d%d", &v[i], &w[i]);
for(int i=1; i<=n; i++)
{
for(int j=m; j>=v[i]; j--)
{
f[j] = max(f[j], f[j-v[i]] + w[i]);
}
}
printf("%d", f[m]);
return 0;
}
完全背包
朴素版
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
//f[i][j]表示前i个物品,体积不超过j时的最大价值
//f[i][j]=max(f[i-1][j], f[i-1][j], f[i-1][j-v[i]]+w[i], f[i-1][j-2*v[i]]+2*w[i], ....)
int f[maxn][maxn] = {}; //默认全为0,这样后面就不需要再初始化
int n = 0, m = 0; //n件物品,m为背包总容量
int v[maxn] = {}, w[maxn] = {}; //v表示第i件物品体积,w为第i件物品价值
int main()
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) scanf("%d%d", &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]);
}
}
}
printf("%d", f[n][m]);
return 0;
}
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
//f[i][j]表示前i个物品,体积不超过j时的最大价值
//f[i][j] = max(f[i-1][j], f[i][j-v] + w)
int f[maxn][maxn] = {}; //默认全为0,这样后面就不需要再初始化
int n = 0, m = 0; //n件物品,m为背包总容量
int v[maxn] = {}, w[maxn] = {}; //v表示第i件物品体积,w为第i件物品价值
int main()
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) scanf("%d%d", &v[i], &w[i]);
for(int i=1; i<=n; i++)
{
for(int j=0; j<=m; j++)
{
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]);
}
}
printf("%d", f[n][m]);
return 0;
}
一维
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int f[maxn] = {}; //默认全为0,这样后面就不需要再初始化
int n = 0, m = 0; //n件物品,m为背包总容量
int v[maxn] = {}, w[maxn] = {}; //v表示第i件物品体积,w为第i件物品价值
int main()
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) scanf("%d%d", &v[i], &w[i]);
for(int i=1; i<=n; i++)
{
for(int j=v[i]; j<=m; j++)
{
f[j] = max(f[j], f[j-v[i]] + w[i]);
}
}
printf("%d", f[m]);
return 0;
}
多重背包
点击查看代码
分组背包
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 40;
const int maxm = 210;
//分组背包
int n = 0, m = 0, t = 0;
int v[maxn] = {}, c[maxn] = {};
//g[i][j]表示第i组第j个物品的编号
int g[15][maxn] = {};
//f[i][j]表示前i组物品,体积不超过j的最大价值
int f[15][maxm] = {};
int main()
{
int x = 0;
scanf("%d%d%d", &m, &n, &t);
for(int i=1; i<=n; i++)
{
scanf("%d%d%d", &v[i], &c[i], &x);
g[x][++g[x][0]] = i;
}
for(int i=1; i<=t; i++)
{
for(int j=0; j<=m; j++)
{
f[i][j] = f[i-1][j];
for(int k=1; k<=g[i][0]; k++)
{
if(j >= v[g[i][k]])
{
x = g[i][k];
f[i][j] = max(f[i][j], f[i-1][j-v[x]] + c[x]);
}
}
}
}
printf("%d", f[t][m]);
return 0;
}
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 40;
const int maxm = 210;
//分组背包
int n = 0, m = 0, t = 0;
int v[maxn] = {}, c[maxn] = {}, g[15][maxn] = {};
int f[maxm] = {};
int main()
{
int x = 0;
scanf("%d%d%d", &m, &n, &t);
for(int i=1; i<=n; i++)
{
scanf("%d%d%d", &v[i], &c[i], &x);
g[x][++g[x][0]] = i;
}
for(int i=1; i<=t; i++)
{
for(int j=m; j>=0; j--)
{
for(int k=1; k<=g[i][0]; k++)
{
if(j >= v[g[i][k]])
{
x = g[i][k];
f[j] = max(f[j], f[j-v[x]] + c[x]);
}
}
}
}
printf("%d", f[m]);
return 0;
}
vector数组存最方便,也可用链式前向行
依赖背包
二维费用背包
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 60;
const int maxm = 410;
//二维费用背包
int n = 0, v = 0, m = 0;
int a[maxn] = {}, b[maxn] = {}, c[maxn] = {};
int f[maxm][maxm] = {};
int main()
{
scanf("%d%d%d", &v, &m, &n);
for(int i=1; i<=n; i++)
{
scanf("%d%d%d", &a[i], &b[i], &c[i]);
}
for(int i=1; i<=n; i++)
{
for(int j=v; j>=a[i]; j--)
{
for(int k=m; k>=b[i]; k--)
{
f[j][k] = max(f[j][k], f[j-a[i]][k-b[i]] + c[i]);
}
}
}
printf("%d", f[v][m]);
return 0;
}
树形背包DP
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int m,n,w[1005],f[1005][1005];
vector <int> a[1005];
void dp(int fa)
{
for(int i=0;i<a[fa].size();i++)
{
int son=a[fa][i];
dp(son);
for(int j=n;j>=0;j--)
for(int k=0;k<=j;k++)
f[fa][j]=max(f[fa][j],f[fa][j-k]+f[son][k]);
}
if(fa)
{
for(int j=n;j>0;j--)
f[fa][j]=f[fa][j-1]+w[fa];
}
}
int main()
{
cin>>m>>n;
int x,y;
for(int i=1;i<=m;i++)
{
cin>>x>>w[i];
a[x].push_back(i);
}
dp(0);
cout<<f[0][n];
return 0;
}
Vector
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int m,n,w[1005],f[1005][1005];
vector <int> a[1005];
void dp(int fa)
{
for(int i=0;i<a[fa].size();i++)
{
int son=a[fa][i];
dp(son);
for(int j=n;j>=0;j--)
for(int k=0;k<j;k++)
f[fa][j]=max(f[fa][j],f[fa][j-k-1]+f[son][k]+w[son]);
}
}
int main()
{
cin>>m>>n;
int x,y;
for(int i=1;i<=m;i++)
{
cin>>x>>w[i];
a[x].push_back(i);//x->i
}
dp(0);
cout<<f[0][n];
return 0;
}
链式前向星
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m,cnt;
int f[200][200];
struct node{
int from;
int to;
int w;
}edge[20000];
int head[2000];
void dfs(int zi,int gen){
for(int i=head[zi];i;i=edge[i].from){
int to=edge[i].to;
dfs(to,zi);
for(int j=m;j>=1;j--){
for(int k=0;k<j;k++){
f[zi][j]=max(f[zi][j],f[edge[i].to][k]+f[zi][j-k-1]+edge[i].w);
}
}
}
}
void add(int from,int to,int w){
cnt++;
edge[cnt].from=head[from];
edge[cnt].to=to;
edge[cnt].w=w;
head[from]=cnt;
}
int main(){
int from,to,w;
cin>>n>>m;
for(int i=1;i<=n-1;i++){
cin>>from>>to>>w;
add(from,to,w);
}
dfs(1,0);
cout<<f[1][m];
}
oi-wiki树形背包DP 树形DP
点击查看代码
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
int f[305][305], s[305], n, m;
vector<int> e[305];
int dfs(int u) {
int p = 1;
f[u][1] = s[u];
for (auto v : e[u]) {
int siz = dfs(v);
// 注意下面两重循环的上界和下界
// 只考虑已经合并过的子树,以及选的课程数超过 m+1 的状态没有意义
for (int i = min(p, m + 1); i; i--)
for (int j = 1; j <= siz && i + j <= m + 1; j++)
f[u][i + j] = max(f[u][i + j], f[u][i] + f[v][j]); // 转移方程
p += siz;
}
return p;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
int k;
scanf("%d%d", &k, &s[i]);
e[k].push_back(i);
}
dfs(0);
printf("%d", f[0][m + 1]);
return 0;
}
注意事项:
标签:总结,背包,int,件物品,maxn,using,include,DP From: https://www.cnblogs.com/wlesq/p/18018133