依赖背包问题

  1. 地址https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4

  2. 代码

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    /**
     * @version V2.1
     * @date 2019/8/14 11:10
     * @since 2.1.0
     */
    public class Main {
    
    
        public static void main(String[] args) {
    
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
    
            try {
    
                String[] input = bufferedReader.readLine().split("\\s+");
                int money = Integer.valueOf(input[0]);
                int itemNum = Integer.valueOf(input[1]);
    
                // 价格
                int[] prices = new int[itemNum];
                // 价值 = 价格*重要度
                int[] values = new int[itemNum];
                // 类型。=0表示主件,>0表示附件,数值为所属的主件,编号从1开始。
                int[] types = new int[itemNum];
                for (int i = 0; i < itemNum; i++) {
                    input = bufferedReader.readLine().split("\\s+");
                    prices[i] = Integer.valueOf(input[0]);
                    values[i] = prices[i] * Integer.valueOf(input[1]);
                    types[i] = Integer.valueOf(input[2]);
                }
    
                // 1.对每一个主件及其所属附件进行01背包。将问题转为分组问题。
                int[][] dps = new int[itemNum][money+1];
                for (int i = 0; i < itemNum; i++) {
                    // 当类型为主件时,对当前主件及其所属附件进行01背包,注意必须选择主件。
                    if (types[i] == 0) {
                        // 记录,对当前主件进行01背包
                        int masterNo = i + 1;
                        // 为所有背包加入主件
                        for (int sum=money; sum >= prices[i]; sum--) {
                            dps[i][sum] = values[i];
                        }
                        for (int j = 0; j < itemNum; j++) {
                            // 类型为附件,主件已经提前加入
                            if (types[j] == masterNo) {
                                // 状态转移方程, 注意这里使用一维数组优化, 所以为倒序。
                                for(int sum=money; sum>= (prices[j]+ prices[i]); sum--) {
                                    // F[v] = MAX(F(v), F(v-C) + W)
                                    dps[i][sum] = Math.max(dps[i][sum], dps[i][sum - prices[j]] + values[j]);
                                }
                            }
                        }
                    }
                }
    
                // 2. 进行分组背包
                int[] dp = new int[money+1];
                // 遍历分组
                for(int i=0; i<itemNum; i++) {
                    // 只需要主件分组
                    if (types[i] == 0) {
                        // 遍历容量, 因为使用一维数组优化,采用倒序遍历
                        for (int v = money; v >= 0; v--) {
                            // 遍历组件中的每件物品
                            for (int k = 0; k <= money; k++) {
                                if (v-k >= 0) {
                                    dp[v] = Math.max(dp[v], dp[v - k] + dps[i][k]);
                                }
                            }
                        }
                    }
                }
    
                System.out.println(dp[money]);
    
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
    
posted @ 2019-08-21 15:15  bosslv  阅读(497)  评论(0编辑  收藏  举报