算法设计与分析之动态规划

今天刚刚学了动态规划,把书上的代码敲了一下,在此留下一笔。动态规划与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。在子问题的求解过程中,有很多子问题被重复计算了。于是我们可以用一个表来记录所有已解决的子问题的的答案。不管该问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划的基本思想。

一、动态规划的设计步骤:

(1)找出最优解的性质,并刻画其结构特征;

(2)递归地定义最优值;

(3)以自顶向下的方式计算出最优值;

(4)根据计算最优值时得到的信息,构造最优解。

下面使用动态规划来解决的是矩阵连乘问题。

问题描述:给定n个矩阵:A1,A2,...,An,其中Ai与Ai+1是可乘的,i=1,2...,n-1。确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数。

第一步分析最优解的结构:

  若将对应m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地由s[i][j]构造出相应的最优解。s[i][j]中的数表明,计算矩阵链A[i:j]的最佳方式应在矩阵Ak和Ak+1之间断开,即最优的加括号方式应为(A[i:k])(A[k+1:j)。因此,从s[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n]),进一步递推,A[1:s[1][n]]的最优加括号方式为(A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]+1:s[1][s[1][n]]])。同理可以确定A[s[1][n]+1:n]的最优加括号方式在s[s[1][n]+1][n]处断开...照此递推下去,最终可以确定A[1:n]的最优完全加括号方式,及构造出问题的一个最优解。

第二步、建立递归关系

设计算A[i:j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]。

当i=j时,A[i:j]=Ai,因此,m[i][i]=0,i=1,2,…,n
      当i<j时,若A[i:j]的最优次序在Ak和Ak+1之间断开,i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。由于在计算是并不知道断开点k的位置,所以k还未定。不过k的位置只有j-i个可能。因此,k是这j-i个位置使计算量达到最小的那个位置。

综上,有递推关系如下:

第三步、计算最优解

最后代码如下:

package algo.chapter3;

import java.io.Serializable;

/**
 * 矩阵相乘
 * @author Administrator
 *
 */
public class MatrixPlus {

    public static void matrixChain(int[] p,int [][]m,int [][]s)
    {
        int n = p.length-1;
        for(int i=1;i<=n;i++)
            m[i][i] = 0;
        for(int r=2;r<=n;r++)
            //对角线上循环的次数
            for(int i=1;i<=n-r+1;i++)
            {
                int j = i+r-1;
                m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];
                s[i][j] = i;
                for(int k=i+1;k<j;k++)
                {
                    int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
                    if(t < m[i][j])
                    {
                        m[i][j] = t;
                        //递归式,记录k的位置
                        s[i][j] = k;
                    }
                }
            }
    }

    public static void traceback(int [][]s,int i,int j)
    {
        if(i == j)
            return;
        traceback(s,i,s[i][j]);
        traceback(s,s[i][j]+1,j);
        System.out.println("Multiply A"+i+"."+s[i][j]+
                "and A"+(s[i][j]+1)+"."+j);
    }

    //打印加括号的最优解方案
    public static void optimalParens(int [][]s,int i,int j)
    {
        if(i==j)
            System.out.print("(A"+i);
        else
        {
            optimalParens(s,i,s[i][j]);
            optimalParens(s,s[i][j]+1,j);
            System.out.print(")");
        }
    }
}

测试代码:

package algo.chapter3.test;

import algo.chapter3.MatrixPlus;

public class MatrixTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int [] p = {39,45,35,15,23,45,67,10,26,37};
        int n = p.length;
        //{{12,3,45,56},{2,4,6,23},{9,87,34,23},{23,45,56,56},{23,3,6,8}}
        int [][] m = new int[n][n];
        int [][] s = new int[n][n];
        MatrixPlus.matrixChain(p, m, s);
        System.out.println("该矩阵阶乘子问题数乘的个数为:");
        for(int i=1;i<m.length;i++)
        {
            for(int j=1;j<m.length;j++)
            {
                if(i>j)
                {
                    System.out.print("----"+"\t");
                }
                else
                {
                    System.out.print(m[i][j]+"\t");
                }
            }
            System.out.println();
        }
        System.out.println();
        System.out.println("该矩阵阶乘子问题数乘的个数为:");
        for(int i=1;i<s.length;i++)
        {
            for(int j=1;j<s.length;j++)
            {
                if(i>j)
                {
                    System.out.print("----"+"\t");
                }
                else
                {
                    System.out.print(s[i][j]+"\t");
                }
            }
            System.out.println();
        }

        System.out.println();
        System.out.println("该矩阵阶乘的最优解为:");
        MatrixPlus.traceback(s, 1, n-1);
        MatrixPlus.optimalParens(s, 1, n-1);
    }

}

最后的运行结果如下图:

参考:http://blog.csdn.net/liufeng_king/article/details/8497607

时间: 2024-10-22 10:29:32

算法设计与分析之动态规划的相关文章

【算法设计与分析】动态规划

1. 斐波那契数列 显然,如果我们打算直接递归计算它的每个值,会有重复计算的部分,这个时候我们可以考虑把得到的值存起来,每次调用. 首先,会自然的想到用数组存下,每次计算下标的前两位的值. 但是随后我们边发现,其实每次都只需要保留最后两个数的值就能计算出下一个数的值了.这样减少了存储空间的占用. 2.计算二项式系数 3. 最优二叉查找树    3.1 来源 如今在输入栏上输入关键字,搜索引擎都会按照以前搜索的关键字记录计算频率,得到用户最有可能想要的输入内容. 如何高效查找带频率的键值,使频率高

(转)常用的算法设计与分析-一夜星辰的博客

算法设计与分析 分治法 思想 1. 将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同.递归地解这些子问题,然后将各子问题的解合并得到原问题的解. 2. divide-and-conquer(P) { if(|P| <= n0)adhoc(P); divide P into samller subinstances P1,P2...,Pk; for(int i = 1;i < k;i++) { yi = divide-and-conquer(Pi); } retu

算法设计与分析基础(第3版)读书笔记(及几处翻译上的错误~~)

算法设计与分析基础(第3版) p16 in-place翻译为'在位'?'就地'更合适点 p38 amortized应翻译为'均摊','摊销'这个词简直莫名其妙(可能因为翻译是做算法交易导致的?) p64 迭代优于递归(迭代始终是增量式的,而递归就没办法增量了,除非能够dump整个运行时栈) p73 通过算法可视化得到一个更好的非递归算法(人的图像认知直觉思维?) p79 验证一个拓扑是环.星.还是团?(这个地方有点意思,因为我想到了动态的Verify) p87 凸包问题:从数据结构上讲,Set<

算法设计与分析(屈婉玲)pdf

下载地址:网盘下载 算法设计与分析本教材为计算机科学技术专业核心课程"算法设计与分析"教材.<算法设计与分析>以算法设计技术和分析方法为主线来组织各知识单元,主要内容包括基础知识.分治策略.动态规划.贪心法.回溯与分支限界.算法分析与问题的计算复杂度.NP完全性.近似算法.随机算法.处理难解问题的策略等.书中突出对问题本身的分析和求解方法的阐述,从问题建模.算法设计与分析.改进措施等方面给出适当的建议,同时也简要介绍了计算复杂性理论的核心内容和处理难解问题的一些新技术. &

算法设计与分析 ------最近对问题与8枚硬币问题

利用减治法实现8枚硬币问题: 参考资料:http://blog.csdn.net/wwj_748/article/details/8863503    算法设计--八枚硬币问题 1 #include "stdafx.h" 2 #include <iostream> 3 #include <stdio.h> 4 using namespace std; 5 6 7 void eightcoin(int arr[]); 8 void compare(int a,in

《计算机算法设计与分析》v4 第1章 算法概述 算法实现题答案

博主今年刚上大三,正好开算法这门课.由于博主本人比较喜欢算法但又比较懒,啃不动算法导论,所以决定拿这本书下手. 这本书是王晓东的第四版<计算机算法设计与分析>.初步打算将每章后面的算法题都用代码实现. 有些题跟某个ACM题目很像,我会把该ACM题的链接贴上.有的题没OJ交所以可能是错的.如有发现,还望指出. 1-1 统计数字问题 http://poj.org/problem?id=2282 这个题要按位分解,一位一位的来处理. #include<iostream> #include

【通知】《算法设计与分析》实验课、理论课补课、考试时间、加分等安排 及 个人目标设定

Logistic回归为概率型非线性回归模型,是研究二分类观察结果与一些影响因素之间关系的一种多 变量分析方法.通常的问题是,研究某些因素条件下某个结果是否发生,比如医学中根据病人的一些症状来判断它是 否患有某种病. 在讲解Logistic回归理论之前,我们先从LR分类器说起.LR分类器,即Logistic Regression Classifier. 在分类情形下,经过学习后的LR分类器是一组权值,当测试样本的数据输入时,这组权值与测试数据按 照线性加和得到 这里是每个样本的个特征. 之后按照s

算法设计与分析——回溯法算法模板

以深度优先方式系统搜索问题解的算法称为回溯法.在回溯法中,解空间树主要分为了四种子集树.排列树.n叉树和不确定树. 在<算法设计与分析课本>中介绍了11个回溯法的问题样例,这里根据解空间树的类型做一个分类. 子集树 装载问题 符号三角形问题 0-1背包问题 最大团问题 算法模板: void backtrack(int t) { if(搜索到叶子结点) { return; } for(i=0; i<=1; i++) //01二叉树 { if(满足约束函数和限界函数)//剪枝 { backt

算法设计与分析-Week12

题目描述 You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the c