zoukankan      html  css  js  c++  java
  • 动态规划-01背包-Tallest Billboard

    2020-02-07 17:46:32

    问题描述:

    问题求解:

    解法一:BF

    看问题规模看似可以直接暴力解决。

    如果直接去解肯定是会超时的,因为每次将原空间划分成A区域,B区域和剩余区域的时间复杂度为O(3 ^ n)。

    但是我们可以将问题进行一下转化,之前有个问题是能否将一个数组中的数划分成两个和相等的子区域那个题目是可以使用dp完成求解的,时间复杂度是O(nsum)。

    因此我们可以去构造出所有的挑选可能,并对每个可能产生解的可能去过一遍dp就能完成本题。

    但是,本解法并不是最优解。

        int ret = 0;
        int[] nums;
        List<Integer> res = new ArrayList<>();
        
        public int tallestBillboard(int[] rods) {
            nums = rods;
            helper(0, 0);
            return ret;
        }
        
        private void helper(int start, int sum) {
            if (start >= nums.length) return;
            if (sum % 2 == 0 && check(res, sum / 2)) {
                ret = sum / 2;
            }
            helper(start + 1, sum);
            res.add(nums[start]);
            sum += nums[start];
            if (sum % 2 == 0 && check(res, sum / 2)) {
                ret = sum / 2;
            }
            helper(start + 1, sum);
            sum -= nums[start];
            res.remove(res.size() - 1);
        }
        
        private boolean check(List<Integer> nums, int target) {
            if (target <= ret) return false;
            int[] dp = new int[target + 1];
            dp[0] = 1;
            for (int num : nums) {
                for (int w = target; w >= num; w--) {
                    dp[w] |= dp[w - num];
                }
            }
            return dp[target] == 1;
        }

    解法二:DP

    事实上,本题可以直接使用dp求解。时间复杂度O(nSum),但是状态的定义有点特殊。

    dp[i][j] : 取前i个数字,diff = j的最大公共区域。

    dp[0][0] = 0, dp[i][j] = -inf

        int inf = (int)1e9;
        public int tallestBillboard(int[] rods) {
            int n = rods.length;
            int sum = 0;
            for (int num : rods) sum += num;
            int[][] dp = new int[n + 1][sum + 1];
            for (int i = 0; i <= n; i++) Arrays.fill(dp[i], -inf);
            dp[0][0] = 0;
            for (int i = 1; i <= n; i++) {
                for (int j = 0; j <= sum - rods[i - 1]; j++) {
                    // not use i
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j]);
                    // put on higher part
                    dp[i][j + rods[i - 1]] = Math.max(dp[i][j + rods[i - 1]], dp[i - 1][j]);
                    // put on lower part
                    dp[i][Math.abs(j - rods[i - 1])] = Math.max(dp[i][Math.abs(j - rods[i - 1])], dp[i - 1][j] + Math.min(j, rods[i - 1]));
                }
            }
            return dp[n][0];
        }
    

      

  • 相关阅读:
    模板实现一个通用栈
    服务器开发
    objectc获取文件各项属性方法
    Visual C++ MFC 中常用宏的含义
    symbian获取中文的拼音
    sip协议的功能及其应用
    【转】MySQL分区的简单实例,用于解决大数据表的问题
    Symbian c++ 在3版中实现并动态配置开机自启动
    (转)如果你也喜欢用goto
    C++实现查找汉字拼音首字母
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/12273950.html
Copyright © 2011-2022 走看看