动态规划习题--九章算法第五、六章习题

1.Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

//如果最终最优路径过该点,从起点到该点的路径中,一定是最优的那条入选最优路径;但是从起点到该点的最优路径不一定是局部最优路径,有可能比同阶段的相邻点大
public class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        int[][] f = new int[n][n];   //因为每步只能走临近的数字,因此横向最长也是跟行数相等

        //初始化
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                f[i][j]=Integer.MAX_VALUE;
            }
        }
        f[0][0]=triangle.get(0).get(0);
        //让f[i][j]代表从起点到i,j点的最小路径
        //最小路径和f[0][n-1]~f[n-1][n-1]的最小值
        for(int i =1;i<n;i++){
            for(int j=0;j<=i;j++){
                if(j==0)
                    f[i][j]=f[i-1][j]+triangle.get(i).get(j);
                else
                    f[i][j]=Math.min(f[i-1][j],f[i-1][j-1])+triangle.get(i).get(j);
            }
        }
        int min=Integer.MAX_VALUE;
        for(int i =0;i<n;i++){
            if(f[n-1][i]<min)
            min=f[n-1][i];
        }
        return min;
    }
}

精简空间度的版本:由于f[i][j]只与f[i-1][j]和f[i-1][j-1]有关,即仅与上一行状态有关因此可仅申请2行的空间,i的处理上%2就好了。如果与前2行有关就%3,....以此类推

 1 public class Solution {
 2     public int minimumTotal(List<List<Integer>> triangle) {
 3         int n = triangle.size();
 4         int[][] f = new int[2][n];   //因为每步只能走临近的数字,因此横向最长也是跟行数相等
 5
 6         //初始化
 7         for(int i=0;i<n;i++){
 8             for(int j=0;j<n;j++){
 9                 f[i%2][j]=Integer.MAX_VALUE;
10             }
11         }
12         f[0][0]=triangle.get(0).get(0);
13         //让f[i][j]代表从起点到i,j点的最小路径
14         //最小路径和f[0][n-1]~f[n-1][n-1]的最小值
15         for(int i =1;i<n;i++){
16             for(int j=0;j<=i;j++){
17                 if(j==0)
18                     f[i%2][j]=f[(i-1)%2][j]+triangle.get(i).get(j);
19                 else
20                     f[i%2][j]=Math.min(f[(i-1)%2][j],f[(i-1)%2][j-1])+triangle.get(i).get(j);
21             }
22         }
23         int min=Integer.MAX_VALUE;
24         for(int i =0;i<n;i++){
25             if(f[(n-1)%2][i]<min)
26             min=f[(n-1)%2][i];
27         }
28         return min;
29     }
30 }

//如果最终最优路径过该点,从起点到该点的路径中,一定是最优的那条入选最优路径;但是从起点到该点的最优路径不一定是局部最优路径,有可能比同阶段的相邻点大
public class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        int[][] f = new int[2][n];   //因为每步只能走临近的数字,因此横向最长也是跟行数相等
         
        //初始化
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                f[i%2][j]=Integer.MAX_VALUE;
            }
        }
        f[0][0]=triangle.get(0).get(0);
        //让f[i][j]代表从起点到i,j点的最小路径
        //最小路径和f[0][n-1]~f[n-1][n-1]的最小值
        for(int i =1;i<n;i++){
            for(int j=0;j<=i;j++){
                if(j==0)
                    f[i%2][j]=f[(i-1)%2][j]+triangle.get(i).get(j);
                else
                    f[i%2][j]=Math.min(f[(i-1)%2][j],f[(i-1)%2][j-1])+triangle.get(i).get(j);
            }
        }
        int min=Integer.MAX_VALUE;
        for(int i =0;i<n;i++){
            if(f[(n-1)%2][i]<min)
            min=f[(n-1)%2][i];
        }
        return min;
    }
}

时间: 2024-08-08 18:42:51

动态规划习题--九章算法第五、六章习题的相关文章

构建之法第五六章读后感

邹欣老师的这本书,写得形象生动,第五章用体育运动等团队例子引出软件开发团队的形式.软件团队形式多样,适用于不同的人员与需求.团队可能会演变的模式有:主治医师模式.明星模式.社区模式.业余剧团模式.秘密团队.特工团队.交响乐团模式.爵士乐模式.功能团队模式.官僚模式等.开发流程模式有:瀑布模式.瀑布模型的各种变形.统一流程.老板驱动的流程.渐进交付的流程等.在过去的学习生活很少有团队合作的时候,看了本章很期待后续与大家团队合作,肯定会遇到很多困难,但只有把学到的运用到实际,知识才会学得更牢靠. 看

《算法》第六章部分程序 part 7

? 书中第六章部分程序,加上自己补充的代码,包括全局最小切分 Stoer-Wagner 算法,最小权值二分图匹配 ● 全局最小切分 Stoer-Wagner 算法 1 package package01; 2 3 import edu.princeton.cs.algs4.In; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.EdgeWeightedGraph; 6 import edu.princ

c++ primer(第五版)学习笔记及习题答案代码版(第六章)函数

笔记较为零散,都是自己不熟悉的知识点. 习题答案至于一个.cc 中,编译需要包含Chapter6.h头文件. 需要演示某一题直接修改 #define NUM***, 如运行6.23题为#define NUM623: chapter 6 1. 形参初始化的机理与变量初始化一样. 当形参是引用类型时,它对应的实参被引用传递或者函数被传引用调用. 2. const和实参 void fcn(const int i){ /*fcn能够读取i,但是不能向i写值*/} void fcn(int i){ /*.

算法导论第六章优先队列(二)

优先队列可以说是堆的一个非常重要的应用,和堆对应,优先队列也分最小优先队列和最大优先队列. 优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中每一个元素都有一个关键字(key),关键字赋予了一个元素的优先级,故名为优先队列.之所以用堆来实现优先队列,我想最大的原因是堆很容易对元素按关键字进行排序. 优先队列的应用: 最大优先队列:其中最为典型的就是“共享计算机系统的作业调度”,通过记录各个作业的优先级,来调度一个作业的执行.删除和插入等操作. 最小优先队列:可以被用于“基于事件驱动的模

算法导论第六章 堆排序

堆的时间复杂度是建O(n),时间复杂度为堆排序O(NLogN),细节如以下的算法看到: #include <iostream> using namespace std; void swap(int &i,int &j) { int temp=i; i=j; j=temp; } void shiftDown(int *A, int start,int len) { int temp=A[start]; int i=start; int j=2*i+1; while (j<l

算法导论 第六章 思考题 6-1 用插入的方法建堆

BUILD-MAX-HEAP'(A) heap-size[A]<-1 for i <- 2 to length[A] do MAX-HEAP-INSERT(A, A[i]) 如上,题目给出一种使用插入的办法建堆的算法,而书中6.4节给出的建堆算法如下: BUILD-MAX-HEAP(A) heap-size[A] <-- length[A] for i <-- length[A] / 2 downto 1 do MAX-HEAPIFY[A, i] 可以发现元素调整的方向恰好反过来了

算法导论第六章堆排序(一)

现在来看, 堆的含义大概有两种,一种是数据结构,一种是在一些语言中所定义的“垃圾回收机制”,如Java,在书本上的开篇强调了这两者,并强调若非特殊说明,皆把堆看做是一种数据结构. (二叉)堆的定义: 1)它是一个数组,可以被看成是一棵近似的完全二叉树,树上的每一个节点看做是数组中的每一个元素. 2)堆分为最大堆和最小堆,最大堆中每一棵子树的父节点的值大于孩子节点,最小堆则相反. 3)表示堆的数组A包括两个属性:A.length和A.heap_size.前者是数组元素的个数,后者是堆元素的个数,h

算法导论 第六章 思考题 6-3 d叉堆

d叉堆的实现相对于二叉堆变化不大,首先看它如何用数组表示. 考虑一个索引从1开始的数组,一个结点i最多可以有d个子结点,编号从id - (d - 2) 到 id + 1. 从而可以知道一个结点i的父结点计算方法为: (i + d - 2) / d. 第二个问题是 一个含有n个元素的d叉堆的高度,就是一个简单的等比数列的问题,可以知道的是一颗高度为h的满d叉树所含的结点数目为(d^(h +1) - 1) / (d - 1) 从而一颗含有 n个结点的d叉树满足的条件为: ,从而得到高度h为: 接下来

算法导论 第六章 思考题6-3 Young氏矩阵

这题利用二叉堆维持堆性质的办法来维持Young氏矩阵的性质,题目提示中写得很清楚,不过确实容易转不过弯来. a,b两问很简单.直接看c小问: 按照Young氏矩阵的性质,最小值肯定在左上角取得,问题在于取出最小值后如何保持矩阵的性质.可以参照max_heapify中的做法,先取出最小值,然后将矩阵左上角置为最大值,这样左上角处的元素必然导致Young氏矩阵的性质违背,于是考虑该元素右边的元素和该元素下边的元素,问题是该与右边元素交换还是与下边元素交换呢?可以发现,如果与T(右)和T(下)中较小的