3/10 动规回顾
3/10 动规回顾
由一道完全背包和多重背包结合的洛谷题引入
key code
const int N=1e4+10;
int n,m;
int a[N],b[N],c[N];
int dp[10010];
void solve(){
//try it again.
// mem1(dp);
int begin=0;
int end=0;
int x;char t;
cin>>x>>t;
begin+=x*60;cin>>x;
begin+=x;
cin>>x>>t;
end+=x*60;cin>>x;
end+=x;
int lenth=end-begin;
m=lenth;
// cout<<lenth<<endl;
dp[0]=0;
cin>>n;
up(1,n){cin>>a[o]>>b[o]>>c[o];}
up(1,n){
if(c[o]==0){
fup(j,a[o],m){
dp[j]=max(dp[j-a[o]]+b[o],dp[j]);
}
}
else{
for(int k=1;k<=c[o];k++){
for(int j=m;j>=a[o];j--){
dp[j]=max(dp[j],dp[j-a[o]]+b[o]);
}
}
}
}
cout<<dp[m]<<endl;
}
回顾一下背包
-
01背包
- 只能选一次,遍历方向与贡献的方向相反
-
完全背包
- 可以选无数次,遍历方向与贡献方向相同
-
多重背包
-
可以选择多次,遍历方向与贡献方向相同且有次数限制
-
一个一个的枚举会浪费大量的时间,我们可以通过枚举二进制状态来压缩时间
-
二进制拆分的板子
-
int tv,tw,s;
cin>>tv>>tw>>s;
int k=1;
while(s>=k){
v[++cnt]=tv*k;
w[cnt]=tw*k;
s-=k;
k*=2;
}
if(s>0){
v[++cnt]=tv*s;
w[cnt]=tw*s;
}
-
分组背包
-
背板子即可
-
板子:
-
cin >> n >> m;
for (int i = 1; i <= n; i ++ ){
cin >> s[i];
for (int j = 0; j < s[i]; j ++ )
cin >> v[i][j] >> w[i][j];
}
for (int i = 1; i <= n; i ++ )
for (int j = m; j >= 0; j -- )
for (int k = 0; k < s[i]; k ++ )
if (v[i][k] <= j)
f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);
cout << f[m] << endl;

浙公网安备 33010602011771号