zoukankan      html  css  js  c++  java
  • 动态规划(java)

    问题一:最大子组和问题
    子组中的元素可能是正负或0,思路:
    最大子组和就是所有可能的子组和中最大的,那么可能比较大的首先有一个初始值(0),然后如果有比初始值大的子组和,就用来替代当前的最大子组和,直到遍历结束再也没有比当前子组和更大的。
    当子组和为负的时候,肯定不是我们期望的最大子组和的一部分,因为负的累积值和后续的子组元素的和,肯定小于后续子组元素的和。这时可以排除该子组和的元素,从使累计子组和为正的开始重新统计。
    当遍历结束最大子组和等于初始值0时,说明数组元素都是非正的,那么遍历找出最大的负数。

    /**
     * @author Flying
     *         题目:输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
     *         求所有子数组的和的最大值。要求时间复杂度为O(n)。 浙大数据结构课本上有 思路:
     *         求连续数字之和,当和为负值,抛弃.当和为正值,比较其与最大值,如大于,则替换之
     *         http://zhedahht.blog.163.com/blog/static/254111742007219147591/
     *         http://blog.csdn.net/v_JULY_v/article/details/6444021
     */
    public class FindMaxSumOfSubArray {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            FindMaxSumOfSubArray f = new FindMaxSumOfSubArray();
            int[] arr = { 1, -2, 3, 10, -4, 7, 2, -5 };
            System.out.println("MaxSum:" + f.findMaxSum(arr));
        }
    
        public Integer findMaxSum(int[] arr) {
            int curSum = 0;
            int maxSum = 0;
            int len = arr.length;
    
            if (arr == null || len == 0) {
                return null;
            }
    
            for (int i = 0; i < len; i++) {
                curSum += arr[i];
                if (curSum < 0) {
                    curSum = 0;
                }
                if (curSum > maxSum) {
                    maxSum = curSum;
                }
            }
    
            // all data are negative
            if (maxSum == 0) {
                for (int i = 0; i < len; i++) {
                    if (i == 0) {
                        maxSum = arr[i];
                    }
                    if (arr[i] > maxSum) {
                        maxSum = arr[i];
                    }
                }
            }
            return maxSum;
        }
    }

    问题二:背包问题
    这是我看过讲背包问题,最容易理解的帖子
    http://m.blog.csdn.net/article/details?id=7722810
    01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }
    f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值。
    Pi表示第i件物品的价值。
    决策:为了背包中物品总价值最大化,第 i件物品应该放入背包中吗 ?

    题目描述:
    有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

    这里写图片描述
    只要你能通过找规律手工填写出上面这张表就算理解了01背包的动态规划算法。
    首先要明确这张表是至底向上,从左到右生成的。
    为了叙述方便,用e2单元格表示e行2列的单元格,这个单元格的意义是用来表示只有物品e时,有个承重为2的背包,那么这个背包的最大价值是0,因为e物品的重量是4,背包装不了。
    对于d2单元格,表示只有物品e,d时,承重为2的背包,所能装入的最大价值,仍然是0,因为物品e,d都不是这个背包能装的。
    同理,c2=0,b2=3,a2=6。
    对于承重为8的背包,a8=15,是怎么得出的呢?
    根据01背包的状态转换方程,需要考察两个值,
    一个是f[i-1,j],对于这个例子来说就是b8的值9,另一个是f[i-1,j-Wi]+Pi;
    在这里,
    f[i-1,j]表示我有一个承重为8的背包,当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值
    f[i-1,j-Wi]表示我有一个承重为6的背包(等于当前背包承重减去物品a的重量),当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值
    f[i-1,j-Wi]就是指单元格b6,值为9,Pi指的是a物品的价值,即6
    由于f[i-1,j-Wi]+Pi = 9 + 6 = 15 大于f[i-1,j] = 9,所以物品a应该放入承重为8的背包
    下面是java实现:
    http://blog.csdn.net/lovesqcc/article/details/5859223

    public class KnapsackProblem {
         /** 指定背包 */ 
        private Knapsack[] bags; 
    
        /** 总承重  */ 
        private int totalWeight; 
    
        /** 给定背包数量  */ 
        private int n; 
    
        /** 前 n 个背包,总承重为 totalWeight 的最优值矩阵  */ 
        private int[][] bestValues; 
    
        /** 前 n 个背包,总承重为 totalWeight 的最优值 */ 
        private int bestValue; 
    
        /** 前 n 个背包,总承重为 totalWeight 的最优解的物品组成 */ 
        private ArrayList<Knapsack> bestSolution; 
    
        public KnapsackProblem(Knapsack[] bags, int totalWeight) { 
            this.bags = bags; 
            this.totalWeight = totalWeight; 
            this.n = bags.length; 
            if (bestValues == null) { 
                bestValues = new int[n+1][totalWeight+1]; 
            } 
        } 
    
        /**
         * 求解前 n 个背包、给定总承重为 totalWeight 下的背包问题
         * 
         */ 
        public void solve() { 
    
            System.out.println("给定背包:"); 
            for(Knapsack b: bags) { 
                System.out.println(b); 
            } 
            System.out.println("给定总承重: " + totalWeight); 
    
            // 求解最优值 
            for (int j = 0; j <= totalWeight; j++) { 
                for (int i = 0; i <= n; i++) { 
    
                    if (i == 0 || j == 0) { 
                        bestValues[i][j] = 0; 
                    }    
                    else  
                    { 
                        // 如果第 i 个背包重量大于总承重,则最优解存在于前 i-1 个背包中, 
                        // 注意:第 i 个背包是 bags[i-1] 
                        if (j < bags[i-1].getWeight()) { 
                            bestValues[i][j] = bestValues[i-1][j]; 
                        }    
                        else  
                        { 
                            // 如果第 i 个背包不大于总承重,则最优解要么是包含第 i 个背包的最优解, 
                            // 要么是不包含第 i 个背包的最优解, 取两者最大值,这里采用了分类讨论法 
                            // 第 i 个背包的重量 iweight 和价值 ivalue 
                            int iweight = bags[i-1].getWeight(); 
                            int ivalue = bags[i-1].getValue(); 
                            bestValues[i][j] =  
                                Math.max(bestValues[i-1][j], ivalue + bestValues[i-1][j-iweight]);       
                        } // else 
                    } //else          
               } //for 
            } //for 
    
            // 求解背包组成 
            if (bestSolution == null) { 
                bestSolution = new ArrayList<Knapsack>(); 
            } 
            int tempWeight = totalWeight; 
            for (int i=n; i >= 1; i--) { 
               if (bestValues[i][tempWeight] > bestValues[i-1][tempWeight]) { 
                   bestSolution.add(bags[i-1]);  // bags[i-1] 表示第 i 个背包 
                   tempWeight -= bags[i-1].getWeight(); 
               } 
               if (tempWeight == 0) { break; } 
            } 
            bestValue = bestValues[n][totalWeight]; 
        } 
    
        /**
         * 获得前  n 个背包, 总承重为 totalWeight 的背包问题的最优解值
         * 调用条件: 必须先调用 solve 方法
         * 
         */ 
        public int getBestValue() {  
            return bestValue; 
        } 
    
        /**
         * 获得前  n 个背包, 总承重为 totalWeight 的背包问题的最优解值矩阵
         * 调用条件: 必须先调用 solve 方法
         * 
         */ 
        public int[][] getBestValues() { 
    
            return bestValues; 
        } 
    
        /**
         * 获得前  n 个背包, 总承重为 totalWeight 的背包问题的最优解值矩阵
         * 调用条件: 必须先调用 solve 方法
         * 
         */ 
        public ArrayList<Knapsack> getBestSolution() { 
            return bestSolution; 
        } 
        public static void main(String[] args) { 
    
            Knapsack[] bags = new Knapsack[] { 
                    new Knapsack(2,13), new Knapsack(1,10), 
                    new Knapsack(3,24), new Knapsack(2,15), 
                    new Knapsack(4,28), new Knapsack(5,33), 
                    new Knapsack(3,20), new Knapsack(1, 8) 
            }; 
            int totalWeight = 12; 
            KnapsackProblem kp = new KnapsackProblem(bags, totalWeight); 
    
            kp.solve(); 
            System.out.println(" -------- 该背包问题实例的解: --------- "); 
            System.out.println("最优值:" + kp.getBestValue());  
            System.out.println("最优解【选取的背包】: "); 
            System.out.println(kp.getBestSolution()); 
            System.out.println("最优值矩阵:"); 
            int[][] bestValues = kp.getBestValues(); 
            for (int i=0; i < bestValues.length; i++) { 
                for (int j=0; j < bestValues[i].length; j++) { 
                    System.out.printf("%-5d", bestValues[i][j]); 
                } 
                System.out.println(); 
            } 
        } 
    
    }
    public class Knapsack {
        /** 背包重量  */ 
        private int weight; 
    
        /** 背包物品价值  */ 
        private int value; 
        /***
         * 构造器
         */ 
        public Knapsack(int weight, int value) { 
            this.value = value; 
            this.weight = weight; 
        } 
        public int getWeight() { 
            return weight; 
        } 
    
        public int getValue() { 
            return value; 
        } 
    
        public String toString() { 
            return "[weight: " + weight + " " + "value: " + value + "]";   
        } 
    
    }

    最长公共子串
    http://blog.csdn.net/biangren/article/details/8038605

  • 相关阅读:
    【tarjan】BZOJ 1051:受欢迎的牛
    【递推】BZOJ 1088: [SCOI2005]扫雷Mine
    【计算几何】多边形
    【贪心】Bzoj 2457:[BeiJing2011]双端队列
    【单调栈】Bzoj 1012: 最大数maxnumber
    [洛谷P3584] POI2015 LAS
    [洛谷P4049] JSOI2007 合金
    [51nod1533] 一堆的堆
    [AGC018E] Sightseeing Plan
    [CF1065E] Side Transmutations
  • 原文地址:https://www.cnblogs.com/zhangdebin/p/5567881.html
Copyright © 2011-2022 走看看