A1937 潜水员的问题(内存优化,填表法与刷表法,01 背包基础)
原链炸了放个链接。
看一眼数据范围不能 VAI,直接暴力做即可。
数据开到 \((42,158)\) 就行,思路同 A9445。
突然发现这不对,比如一维大一维小,会导致存储其中一维超过二倍。
存储整个存不下,于是让边界值代指边界即其以上。
然后分讨转移。
#include<bits/stdc++.h>
using namespace std;
int O,N,n,dp[23][81];
int main(){
scanf("%d%d%d",&O,&N,&n);
for(int i=0;i<=O;i++) for(int j=0;j<=N;j++) dp[i][j]=1e9;
dp[0][0]=0;
for(int i=1,V_O,V_N,m;i<=n;i++){
scanf("%d%d%d",&V_O,&V_N,&m);
for(int j=O;j==O||j>=V_O;j--) for(int k=N;k==N||k>=V_N;k--)
if(j==O&&k==N)
for(int a=O;a>=0&&a>=O-V_O;a--) for(int b=N;b>=0&&b>=N-V_N;b--)
dp[j][k]=min(dp[j][k],dp[a][b]+m);
else if(j==O)
for(int a=O;a>=0&&a>=O-V_O;a--)
dp[j][k]=min(dp[j][k],dp[a][k-V_N]+m);
else if(k==N)
for(int b=N;b>=0&&b>=N-V_N;b--)
dp[j][k]=min(dp[j][k],dp[j-V_O][b]+m);
else
dp[j][k]=min(dp[j][k],dp[j-V_O][k-V_N]+m);
}
printf("%d\n",dp[O][N]);
return 0;
}
抄了一下题解,发现其他人用的都是刷表法。
这题双倒序枚举可以保证正确性,用这个更简单,简化不少流程,写在这里。
#include<bits/stdc++.h>
using namespace std;
int O,N,n,dp[23][81];
inline void Min(int &a,int b){a=min(a,b);}
int main(){
scanf("%d%d%d",&O,&N,&n);
for(int i=0;i<=O;i++) for(int j=0;j<=N;j++) dp[i][j]=1e9;
dp[0][0]=0;
for(int i=1,V_O,V_N,m;i<=n;i++){
scanf("%d%d%d",&V_O,&V_N,&m);
for(int j=O;j>=0;j--) for(int k=N;k>=0;k--)
Min(dp[min(O,j+V_O)][min(N,k+V_N)],dp[j][k]+m);
}
printf("%d\n",dp[O][N]);
return 0;
}

浙公网安备 33010602011771号