背包DP
0-1 背包
P2871 [USACO07DEC] Charm Bracelet S
https://www.luogu.com.cn/problem/P2871
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long;
using u64 = unsigned long long; const int inf = 2147483647; const ll INF = 1e18;
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n,m; cin>>n>>m; vector<vector<int>>dp(n+1,vector<int>(m+1)); for(int i=1;i<=n;i++) { int v,w; cin>>v>>w; for(int j=1;j<=m;j++) { if(j>=v)dp[i][j]=max(dp[i-1][j],dp[i-1][j-v]+w); else dp[i][j]=dp[i-1][j]; } } cout<<dp[n][m]<<'\n';
return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long;
using u64 = unsigned long long; const int inf = 2147483647; const ll INF = 1e18;
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n,m; cin>>n>>m; vector<int>dp(m+1); for(int i=1;i<=n;i++) { int w,d; cin>>w>>d; for(int j=m;j>=w;j--) { dp[j]=max(dp[j],dp[j-w]+d); } } cout<<dp[m]<<'\n';
return 0; }
|
完全背包
P1616 疯狂的采药
https://www.luogu.com.cn/problem/P1616
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long;
using u64 = unsigned long long; const int inf = 2147483647; const ll INF = 1e18;
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int m,n; cin>>m>>n; vector<vector<ll>>dp(n+1,vector<ll>(m+1)); for(int i=1;i<=n;i++) { int v,w; cin>>v>>w; for(int j=1;j<=m;j++) { if(j>=v)dp[i][j]=max(dp[i-1][j],dp[i][j-v]+w); else dp[i][j]=dp[i-1][j]; } } cout<<dp[n][m]<<'\n'; return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long;
using u64 = unsigned long long; const int inf = 2147483647; const ll INF = 1e18;
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int m,n; cin>>m>>n; vector<ll>dp(m+1); for(int i=1;i<=n;i++) { int a,b; cin>>a>>b; for(int j=a;j<=m;j++)dp[j]=max(dp[j],dp[j-a]+b); } cout<<dp[m]<<'\n'; return 0; }
|
多重背包
P1776 宝物筛选
https://www.luogu.com.cn/problem/P1776
这一题很傻鸟,他先给的物品的价值,再给的物品的重量,所以要cin>>w>>v>>s;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long;
using u64 = unsigned long long; const ll inf = 2147483647; const ll INF = 1e18; signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n,m; cin>>n>>m; vector<ll>dp(m+1); for(int i=1;i<=n;i++) { int w,v,g; cin>>w>>v>>g; for(int j=m;j>=v;j--) { for(int k=1;k<=g;k++) { if(j>=k*v)dp[j]=max(dp[j],dp[j-k*v]+k*w); else break; } } } cout<<dp[m]<<'\n'; return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long;
using u64 = unsigned long long; const ll inf = 2147483647; const ll INF = 1e18; struct node { int v,w; }; signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n,m; cin>>n>>m; vector<ll>dp(m+1); vector<node>goods; for(int i=1;i<=n;i++) { int w,v,s; cin>>w>>v>>s; for(int j=1;j<=s;j<<=1) { s-=j; goods.push_back({j*v,j*w}); } if(s)goods.push_back({s*v,s*w}); } for(auto node:goods) { for(int j=m;j>=node.v;j--) { dp[j]=max(dp[j],dp[j-node.v]+node.w); } } cout<<dp[m]<<'\n'; return 0; }
|
混合背包
混合背包就是把01背包,完全背包,多重背包合在一起了,如果对前面理解透彻的话这个应该也没有什么问题。
如果是用二维DP数组递推的话,01背包是从左上方递推而来,完全背包是从同一层的左边递推而来,而多重背包则是一种特殊的01背包,由多个符合条件的左上方递推而来,多了一个循环遍历个数而已
P1833 樱花
https://www.luogu.com.cn/problem/P1833
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long;
using u64 = unsigned long long; const ll inf = 2147483647; const ll INF = 1e18;
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); string a,b; cin>>a>>b; int n; cin>>n; int zuo=0,you=0; if(a.size()==4)zuo=(a[0]-'0')*60+stoi(a.substr(2)); else zuo=(stoi(a.substr(0,2))*60+stoi(a.substr(3))); if(b.size()==4)you=(b[0]-'0')*60+stoi(b.substr(2)); else you=(stoi(b.substr(0,2))*60+stoi(b.substr(3))); int m=you-zuo; vector<ll>dp(m+1); for(int i=1;i<=n;i++) { int v,w,s; cin>>v>>w>>s; if(s==0) { for(int j=v;j<=m;j++)dp[j]=max(dp[j],dp[j-v]+w); } else if(s==1) { for(int j=m;j>=v;j--)dp[j]=max(dp[j],dp[j-v]+w); } else { for(int j=m;j>=v;j--) { for(int k=1;k<=s;k++) { if(j>=k*v)dp[j]=max(dp[j],dp[j-k*v]+k*w); } } } } cout<<dp[m]<<'\n'; return 0; }
|
二维费用背包
二维费用背包基本上和一维的01背包是一样的,只不过多开了一个维度而已
P1855 榨取kkksc03
https://www.luogu.com.cn/problem/P1855
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long;
using u64 = unsigned long long; const ll inf = 2147483647; const ll INF = 1e18;
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n,m,t; cin>>n>>m>>t; vector<vector<int>>dp(m+1,vector<int>(t+1)); for(int i=1;i<=n;i++) { int a,b; cin>>a>>b; for(int j=m;j>=a;j--) { for(int k=t;k>=b;k--) { dp[j][k]=max(dp[j][k],dp[j-a][k-b]+1); } } } cout<<dp[m][t]<<'\n'; return 0; }
|
分组背包
分组背包也是从左上角递推过来,只不过这个是由一组中的多个物品分别递推而来,而多重背包是由第i个物品的第k倍递推而来
P1757 通天之分组背包
https://www.luogu.com.cn/problem/P1757
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long;
using u64 = unsigned long long; const ll inf = 2147483647; const ll INF = 1e18; struct node { int v,w; }; signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n,m; cin>>m>>n; vector<ll>dp(m+1); int k=-inf; vector<vector<node>>a(n+1); for(int i=1;i<=n;i++) { int v,w,s; cin>>v>>w>>s; k=max(k,s); a[s].push_back({v,w}); } for(int i=1;i<=k;i++) { for(int j=m;j>=1;j--) { for(auto [v,w]:a[i]) { if(j>=v)dp[j]=max(dp[j],dp[j-v]+w); } } } cout<<dp[m]<<'\n'; return 0; }
|
有依赖的背包
P1064 [NOIP2006 提高组] 金明的预算方案
https://www.luogu.com.cn/problem/P1064
这一题有一说一感觉也是一种分组背包,只不过需要细分进行讨论而已。因为一个物品的附属物品最多只有两件,所以可以直接枚举进行讨论。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include<bits/stdc++.h> using namespace std; using u32 = unsigned; #define i128 __int128; using ll = long long; using u64 = unsigned long long; const int inf = 2147483647; const ll INF = 1e18; struct node { int v,p,q; int jz; }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int m,n; cin>>m>>n; vector<node>v(n+1); vector<vector<int>>adj(n+1); vector<ll>dp(m+1); for(int i=1;i<=n;i++) { cin>>v[i].v>>v[i].p>>v[i].q; v[i].jz=v[i].v*v[i].p; if(v[i].q)adj[v[i].q].push_back(i); } for(int i=1;i<=n;i++) { if(v[i].q)continue; for(int j=m;j>=v[i].v;j--) { dp[j]=max(dp[j],dp[j-v[i].v]+v[i].jz); if(adj[i].size()==2) { if(j>=v[i].v+v[adj[i][0]].v)dp[j]=max(dp[j],dp[j-v[i].v-v[adj[i][0]].v]+v[i].jz+v[adj[i][0]].jz);
if(j>=v[i].v+v[adj[i][0]].v+v[adj[i][1]].v)dp[j]=max(dp[j],dp[j-v[i].v-v[adj[i][0]].v-v[adj[i][1]].v]+v[i].jz+v[adj[i][0]].jz+v[adj[i][1]].jz);
if(j>=v[i].v+v[adj[i][1]].v)dp[j]=max(dp[j],dp[j-v[i].v-v[adj[i][1]].v]+v[i].jz+v[adj[i][1]].jz); } else if(adj[i].size()==1) { if(j>=v[i].v+v[adj[i][0]].v)dp[j]=max(dp[j],dp[j-v[i].v-v[adj[i][0]].v]+v[i].jz+v[adj[i][0]].jz); } } } cout<<dp[m]<<'\n'; return 0; }
|