zoukankan      html  css  js  c++  java
  • 蓝桥杯 算法训练 ALGO-116 最大的算式

    算法训练 最大的算式  
    时间限制:1.0s   内存限制:256.0MB
    问题描述
      题目很简单,给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大。因为乘号和加号一共就是N-1个了,所以恰好每两个相邻数字之间都有一个符号。例如:
      N=5,K=2,5个数字分别为1、2、3、4、5,可以加成:
      1*2*(3+4+5)=24
      1*(2+3)*(4+5)=45
      (1*2+3)*(4+5)=45
      ……
    输入格式
      输入文件共有二行,第一行为两个有空格隔开的整数,表示N和K,其中(2<=N<=15, 0<=K<=N-1)。第二行为 N个用空格隔开的数字(每个数字在0到9之间)。
    输出格式
      输出文件仅一行包含一个整数,表示要求的最大的结果
    样例输入
    5 2
    1 2 3 4 5
    样例输出
    120
    样例说明
      (1+2+3)*4*5=120
     

    题目解析:

      本题涉及到一种算法——动态规划。

      (1)动态规划思想

      在分治求解过程中,有些子问题被重复计算了许多次。如果能够保存已解决的子问题的答案,而在需要时再找出,就可以避免大量重复问题的计算,从而得到多项式时间算法。
      (2)设计动态规划的步骤 
          ① 找出最优解的性质,并刻画其结构特征;
          ② 递归地定义最优值(写出动态规划方程);
          ③ 以自底向上的方式计算出最优值(填入表格);
          ④ 根据计算最优值时得到的信息,构造一个最优解。
        说明:  a.步骤 ① ~ ③ 是动态规划算法的基本步骤;
             b.在只需要求出最优值的情况,步骤 ④ 可以省略;若需要求出一个最优解,则必须要有第 ④ 步。
      (3)动态规划的特征
        ① 最优子结构
            当问题的最优解包含了其子问题的最优解,称该问题具有最优子结构性质。
        ② 重叠子问题
            在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。动态规划算法正是利用了这种子问题的重要性质,对每一个子问题只求        解一次,而后将其解保存在一个表格中,在以后尽可能多地利用这些子问题。
     
      以题目给出的样例输入为例,分析动态规划算法:
      (1)利用 sum 数组将前 i 个数之和保存。
        
      (2)利用 dp 数组来保存前 i 个数有 0 个乘号时的最大值(全加时的值,与 sum 数组相同),即 dp[i][0];
        
      (3)在动态规划算法中,从第二( i 从 2 开始)个数后开始加乘号,前 i 个数循环累加 i - 1 (j 从 1 开始,到 i -1 结束,且不能大于 k)个乘号,乘号位置循环从第一个数后的位置到第 i 个数前的位置(p 从 2 开始, 到 i 结束);
       step 1:  i = 2    j = 1    p = 2     说明:前两个数,有一个乘号,位置在第二个数前面
            dp[2][1] = 0                说明:前两个数一个乘号时,值为 0 (表1.2中 dp[2][1])
            dp[1][0] x ( sum[2] - sum[1] ) = 2  说明:前一个数没有乘号乘上前两个数之和减去前一个数之和,即前一个数乘第二个数(1*2 = 2)
            dp[2][1] = max( 0 , 2 )         说明:填入 dp 表中
            
       step 2:  i = 3    j = 1    p = 2     说明:前三个数,有一个乘号,位置在第二个数前面
            dp[3][1] = 0                说明:前三个数一个乘号时,值为 0 (表1.2中 dp[3][1])
            dp[1][0] x ( sum[3] - sum[1] ) = 2  说明:前一个数没有乘号乘上前三个数之和减去前一个数之和,即前一个数乘前两个数之和(1*(2+3) = 5)
            dp[3][1] = max( 0 , 5 )         说明:填入 dp 表中
             
     
       step 3:  i = 3    j = 1    p = 3     说明:前三个数,有一个乘号,位置在第三个数前面
            dp[3][1] = 5                说明:前三个数一个乘号时,值为 0 (表1.2中 dp[3][1])
            dp[2][0] x ( sum[3] - sum[2] ) = 9  说明:前两个数没有乘号乘上前三个数之和减去前两个数之和,即前一个数乘第三个数之和((1+2)* 3) = 9)
            dp[3][1] = max( 5 , 9 )         说明:填入 dp 表中
            
       . . . . . .
       只到所有的循环执行结束,一共 19 步。dp 表最终结果为:
            
       当 5 个数有 2 个乘号时,最大值应为 dp[5][2] = 120。在循环执行过程中,我们不用担心 dp[p-1][j-1] * (sum[i] - sum[p-1]) 究竟是那几个数得到的结果,而使用它的值就可以啦,这就是动态规划最重要的特性之一!
     
    示例代码:
     1 import java.io.BufferedReader;
     2 import java.io.IOException;
     3 import java.io.InputStreamReader;
     4 
     5 public class Main {
     6     public static void main(String[] args) throws IOException {
     7         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
     8         String[] str = br.readLine().split(" ");
     9         int n = Integer.parseInt(str[0]);
    10         int k = Integer.parseInt(str[1]);
    11         
    12         long[][] dp = new long[n+1][k+1];    //dp[i][j]表示前i个数中有j个乘号时,所得最大值
    13         int[] sum = new int[n+1];        //前i个数之和
    14         
    15         str = br.readLine().split(" ");
    16         for(int i = 1; i <= n; i++) {
    17             sum[i] =  sum[i-1] + Integer.parseInt(str[i-1]);
    18         }
    19         
    20         //没有乘号的情况,即连加的情况
    21         for(int i = 1; i <= n; i++) {
    22             dp[i][0] = sum[i];
    23         }
    24         //动态规划
    25         for(int i = 2; i <= n; i++) {                    //前i个数
    26             for(int j = 1; j <= i-1 && j <= k; j++) {    //乘号的个数
    27                 for(int p = 2; p <= i; p++) {            //乘号的位置
    28                     dp[i][j] = max(dp[i][j], dp[p-1][j-1] * (sum[i] - sum[p-1]));//求前i个数有j个乘号时的最大值
    29                 }
    30             }
    31         }
    32         
    33         System.out.println(dp[n][k]);
    34     }
    35 
    36     /**
    37      * 求最大数
    38      * @param a    参数1
    39      * @param b    参数2
    40      * @return    a b中的最大数
    41      */
    42     private static long max(long a, long b) {
    43         return a>b?a:b;
    44     }
    45 }
  • 相关阅读:
    RQNOJ 34 紧急援救
    Codevs 2080 特殊的质数肋骨
    POJ2975 Nim
    Bzoj1016 最小生成树计数
    POJ3613 Cow Relays
    POJ1386 Play on Words
    [从hzwer神犇那翻到的模拟赛题] 合唱队形
    HDU2824 The Euler function
    HDU1576 A/B
    HDU2669 Romantic
  • 原文地址:https://www.cnblogs.com/cao-lei/p/6690827.html
Copyright © 2011-2022 走看看