蓝桥杯Java ABC组 AcWing P1020 潜水员

题目链接:
https://www.acwing.com/problem/content/1022/

#二维背包 #Model #Favorite

思路

好题!

可以让你思考各种背包问题中,对体积的定义不同,则初始化就不同

本题求的是是至少需要体积 V V V,重量 M M M 的情况下,能拿到价值的最小值。

就拿体积来说,至少需要多少体积,也就是说有体积比需要的体积大的物品还是能用得到,例如 f[3][5],至少需要 3 个体积,5 个重量,求能拿到价值的最小值,现在只有一个物品,体积是 4,重量是 4,价值 w w w,它说至少需要 3 个体积,那么体积是 4 还是可以用到,只是多了 1 个体积没用占着而已,不影响其价值,此时 f[-1][1] 这个状态是合法的。

因此若用了这个物品,则变成了求 f[0][1] + w,表示体积已经不再需求了,只需要 0 个体积即可

f[0][i] 代表的意思是体积大于等于 0,重量大于等于 i 时价值的最小值

可以认为在至少的语义上,物品的体积上限是没有限制的,反而是物品体积的下限需要有限制

下面是总结:

求最大值最小值初始化总结
二维情况
1、体积至多jf[i,k] = 00 <= i <= n, 0 <= k <= m(只会求价值的最大值)
2、体积恰好j,
当求价值的最小值:f[0][0] = 0, 其余是INF
当求价值的最大值:f[0][0] = 0, 其余是-INF
3、体积至少jf[0][0] = 0,其余是INF(只会求价值的最小值)

一维情况
1、体积至多j,f[i] = 0, 0 <= i <= m(只会求价值的最大值)
2、体积恰好j,
当求价值的最小值:f[0] = 0, 其余是INF
当求价值的最大值:f[0] = 0, 其余是-INF
3、体积至少j,f[0] = 0,其余是INF(只会求价值的最小值)

[!summary]
可以这么思考,初始化的过程就是定义状态是否合法的过程

  • 体积最多为 j,则像 f[0][j] 是合法情况
  • 体积恰好为 j,则像 f[0][j] 是不合法的情况,因为不放物品时体积不会恰好为一个非 0 数
  • 体积最少为 j,则像 f[0][j] 是不合法情况

代码

import java.io.*;  
import java.util.*;  
import static java.lang.Math.*;  
  
public class Main {  
  
    static int status;  
    static BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));  
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));  
    static PrintWriter cout = new PrintWriter(bw);  
    static StreamTokenizer st = new StreamTokenizer(buf);  
  
    public static int nextInt() throws IOException {  
        status = st.nextToken();  
        return (int) st.nval;  
    }  
  
    public static long nextLong() throws IOException {  
        status = st.nextToken();  
        return (long) st.nval;  
    }  
  
    public static String nextString() throws IOException {  
        status = st.nextToken();  
        return st.sval;  
    }  
  
    static int n, v, m;  
    static int[][] f;  
    static int[] a,b,c;  
    static final int INF = Integer.MAX_VALUE-666666;  
  
    public static void main(String[] args) throws IOException {  
        v = nextInt();  
        m = nextInt();  
        n = nextInt();  
        a = new int[n + 1];  
        b = new int[n + 1];  
        c = new int[n + 1];  
        f = new int[v+1][m+1];  
  
        for(int i=1;i<=n;i++){  
            a[i] = nextInt();  
            b[i] = nextInt();  
            c[i] = nextInt();  
        }  
  
        for(int i=0;i<=v;i++)  
            for(int j=0;j<=m;j++)  
                f[i][j]=INF;  
        f[0][0]=0;  
  
        for(int i=1;i<=n;i++)  
            for(int j=v;j>=0;j--)  
                for(int k=m;k>=0;k--)  
                    f[j][k]=min(f[j][k],f[max(0,j-a[i])][max(0,k-b[i])]+c[i]);  
  
        cout.println(f[v][m]);  
        cout.flush();  
    } // End of main  
}
  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值