最近没写DP,回来写几道水题。
P1064 金明的预算方案
有连带条件的背包问题,对于每个非叶子节点,他的每一个儿子的组合方式都可以枚举跑,类似于树形DP但简单的多
对于每个父亲,选择1号儿子,选择2号儿子,12儿子都选,都不选,或者是自己都不选(写转移时体现在MAX)
注意下标越界和末状态,以及代码构造技巧。
#include<bits/stdc++.h> using namespace std; int n,m,mw[65],mc[65],aw[65][5] ,ac[65][5],f[50000]; int main(){ ios::sync_with_stdio(false); cin>>n>>m; for(int i=1;i<=m;i++){ int v,p,q; cin>>v>>p>>q; if(!q){ mw[i] = v; mc[i] = v * p; } else { aw[q][0] ++; aw[q][aw[q][0]] = v; ac[q][aw[q][0]] = v * p; } } for(int i=1;i<=m;i++){ for(int j=n;mw[i] != 0 && j >= mw[i];j--){//倒序 01背包 f[j] = max(f[j] , f[j - mw[i]] + mc[i]); if(j >= mw[i] + aw[i][1]) f[j] = max(f[j],f[j-mw[i]-aw[i][1]] + mc[i] + ac[i][1]); if(j >= mw[i] + aw[i][2]) f[j] = max(f[j],f[j-mw[i]-aw[i][2]] + mc[i] + ac[i][2]); if(j >= mw[i] + aw[i][1] + aw[i][2]) f[j] = max(f[j],f[j-mw[i]-aw[i][1]-aw[i][2]] + mc[i] + ac[i][1] + ac[i][2]); } } cout<<f[n]<<endl; return 0; }
P1049 装箱问题
我傻了,刚看到时还以为是什么恰好背包,谢罪谢罪.......
#include<bits/stdc++.h> using namespace std; const int MAXN = 35,MAXM = 20010; int n,a[MAXN],f[MAXM],m; int main(){ ios::sync_with_stdio(false); cin>>n>>m; for(int i=1;i<=m;i++){ cin>>a[i]; } for(int i = 1;i<=m;i++){ int nv = a[i]; for(int j = n;j>=nv;j--){ f[j] = max(f[j] , f[j-nv] + nv); } } cout<<n-f[n]<<endl; return 0; }
P1455 搭配购买
我也想买云朵...(你写的题怎么都这么水啊)
并查集,合并物品,背包,perfect。
等等让我去看看并查集怎么写(打死自己)
#include<bits/stdc++.h> using namespace std; const int MAXN = 10100;//第一次数组还开小了 struct RAINBOW{ int cos,val; }a[MAXN],b[MAXN]; int n,m,v,fa[MAXN],f[MAXN]; int find(int x){ return (fa[x] == x) ? x : fa[x] = find(fa[x]); } int main(){ ios::sync_with_stdio(false); cin>>n>>m>>v; for(int i=1;i<=n;i++){ cin>>a[i].cos>>a[i].val; } for(int i=1;i<=n;i++) fa[i] = i; for(int i=1;i<=m;i++){ int x,y; cin>>x>>y;
//蒟蒻自裁 这里并查集写错导致WA了一次 if(find(x) != find(y)) fa[find(x)] = y;//是合并他们的父亲 不是儿子简单连边 } for(int i=1;i<=n;i++){ int now = find(i); b[now].cos += a[i].cos; b[now].val += a[i].val; } for(int i=1;i<=n;i++){ if(b[i].val){ for(int j=v;j>=b[i].cos;j--){ f[j] = max(f[j],f[j-b[i].cos] + b[i].val); } } } cout<<f[v]<<endl; return 0; }
P1910 L国的战斗之间谍
第一眼:什么东西?
然后仔细看觉得应该就是个强制压掉一位的01背包
一看数据范围1000*1000 空间应该是对的吧
然后就A了 注意循环时的顺序和下标爆炸问题
但是蒟蒻跑了4000ms被爆踩
#include<bits/stdc++.h> using namespace std; const int MAXN = 105,MAXM = 1010; struct PEOPLE{ int val,cov,cos; }a[MAXN]; int n,c,v; int f[MAXM][MAXM]; int main(){ ios::sync_with_stdio(false); cin>>n>>c>>v; for(int i=1;i<=n;i++){ cin>>a[i].val>>a[i].cov>>a[i].cos; } for(int i=1;i<=n;i++){ for(int k=c;k>=a[i].cov;k--){ for(int l=v;l>=a[i].cos;l--){ f[k][l] = max(f[k][l],f[k-a[i].cov][l-a[i].cos] + a[i].val); } } } cout<<f[c][v]<<endl; return 0; }
P1510 精卫填海
水题,直接跑压掉第几个石头的01背包
最后遍历最后一行统计答案
#include<bits/stdc++.h> using namespace std ; const int MAXN = 10010; int v,n,c; struct STONE{ int v,cos; }a[MAXN]; int f[MAXN];//tag->cos f[]->v int main(){ ios::sync_with_stdio(false); cin>>v>>n>>c; for(int i=1;i<=n;i++) { cin>>a[i].v>>a[i].cos; } for(int i=1;i<=n;i++) { for(int j=c;j>=a[i].cos;j--){ f[j] = max(f[j],f[j-a[i].cos] + a[i].v); } } int ans = -1; for(int i=1;i<=c;i++){ if(f[i] >= v) ans = max(ans,c-i); } if(ans == -1){ cout<<"Impossible"<<endl; return 0; } cout<<ans<<endl; return 0; }
持续更新
TAG:SIN_XIII ⑨