动态规划(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

posted on 2016-04-24 16:06  决心1119  阅读(259)  评论(0编辑  收藏  举报

导航