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;
}
posted @ 2026-02-15 17:07  2025ing  阅读(0)  评论(0)    收藏  举报