PAT练习题(甲级) 1007 Maximum Subsequence Sum (25分)(简要理解动态规划)(Java实现)

题干

Given a sequence of K integers { N1, N2, …, NK}. A continuous subsequence is defined to be { N​i, Ni+1, …, Nj} where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.

Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.

Input Specification:
Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (≤10000). The second line contains K numbers, separated by a space.

Output Specification:
For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.

Sample Input:
10
-10 1 2 3 4 -5 -23 3 7 -21

Sample Output:
10 1 4

题意

  • 第一行是总共有多少个元素,也就是第二行的数组的长度,记为K。
  • 第二行是数组元素。
  • 输出第一项是子序列的最大和,第二项是子序列的左端,第三项是子序列的右端。

思路分析

  • 因为是求子序列相关问题,所以动态规划可能会比较合适。
  • 有两种情况:
    • 第一种:只有一个元素是正数,那么它就是我们需要的结果。
    • 第二种:正常求解,所求子序列中含有多个元素。
  • 将所求记为dp[i],那么状态转移方程为dp[ i ] = max{list[ i ] , dp[ i - 1 ] + list[ i ]},边界为dp[ 0 ] = list[ 0 ]
  • 在代码实现上就很简单了,很多同学在平常都使用过,可能没有仔细研究过。
  • C和C++的实现也与Java的相同,只不过语句变了,但是C和C++在时间上有着巨大的优势。

理解动态规划

  • 动态规划常见的有三类问题,我在刷题的过程中也有遇到过。
  • 在这里稍微根据网上的文档和自己的理解说一说。

动态规划思想(这类问题的特点)

  • 重叠子问题:例如一个公司中,经理想了解公司各个部门中业务最出色的员工,那么部门的负责人也要了解部门最出色的员工,这个时候会发生问题重叠,虽然是一个问题,但需要两个人进行了解。一个子问题的答案会在后续的求解中多次使用。
  • 最优子结构:这道题就可以理解为最优问题,最优问题就相当于是选取最优子结构。
  • 无后效性:已求出的子问题的答案不会因为后续问题的求解发生改变。

三种模型

  • 线性模型:可参考斐波那契数列的递推式,数组中的递增或递减子序列问题。
  • 区间模型:将问题分为子问题,然后通过所有子问题的求解。
  • 树状模型:数据结构里的树的最优解等问题。

求解的步骤

  • 划分阶段:对问题进行划分,划分的标准是求解问题的顺序,也就是逻辑顺序,划分后的子问题应该是可排序的。(我看有的文档里写的是:按照问题的时间或空间特征,把问题分为若干个阶段。)
  • 确认状态和状态变量:将子问题在整个求解流程中的状态确定,要满足无后效性,即未来不会改变。
  • 确定决策和写出状态转移方程:通过上一阶段的状态和决策来推导出当前阶段的状态,我感觉类似于递归.(在此处可以参考斐波那契数列)(一个优秀博主的帖子上的解释:如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两个阶段的状态之间的关系来确定决策方法和状态转移方程。)
  • 寻找边界条件:一般来讲转移状态方程是个递推式,需要制定一个终止条件或边界。

实现动态规划算法的两种思路

  • 自底向上(自下而上):通过不断的解决问题的子问题最终获取问题的解决方案,类似于迭代
  • 自顶向下(自上而下):通过不断分解问题至最小子问题,然后解决子问题,逆向返回保存答案即可获得问题的解决方案,类似于递归
  • 这两种方法都可以根据问题的实际情况进行优化,例如求解斐波那契数列的时候通过获取每一次递归的结果来加速递归的过程,而不是每一次递归都进行一遍相同的运算。

题目代码实现(有注释)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @Author: 胡奇夫
 * @QQ: 1579328766
 * @CreateTime: 2020-05-10-17-28
 * @Descirption: PAT练习题1007 Maximum Subsequence Sum (25分)
 */
public class Testseven {
    static int sum = 0;//数组中元素的和,在后面for循环中使用,用于和max比较
    static int max = -1;//题目中所求的最大和,因为题中说明当最大和小于零时,只需要输出0即可,所以设置max为-1,便于比较
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s = br.readLine();
        int K = Integer.parseInt(s);//K为输入数字的个数,也就是输入的第一行
        String[] strlist = br.readLine().split(" ");
        int[] list = new int[K];//输入的第二行,共有K个数字
        int left = 0;//最大和的左侧索引
        int right = K-1;//最大和的右侧索引
        int temp = 0;//进行动态规划时的子数组的左侧索引,当max>0时将题目所求的左侧索引temp赋值给left

        //使用for循环转化成int数组
        for(int i = 0;i<K;i++)
        {
            list[i] = Integer.parseInt(strlist[i]);
        }

        //进行动态规划,通过索引分割出所求子数组
        for(int i = 0;i<K;i++)
        {
            sum+=list[i];
            if(sum<0)
            {
                sum = 0;//这里是用来求最大和,所以当sum小于0时进行重置
                temp=i+1;
            }
            else if(sum>max)
            {
                max = sum;
                left = temp;
                right = i;
            }
        }
        if(max<0) max = 0;//因为sum赋值给max,所以当max<0时令max=0
        System.out.println(max+" "+list[left]+" "+list[right]);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45062103/article/details/106038910