• Luogu P2308 添加括号 (DP)


    题目

    题目背景

    给定一个正整数序列a(1)a(2)...a(n),(1<=n<=20)

    不改变序列中每个元素在序列中的位置,把它们相加,并用括号记每次加法所得的和,称为中间和。

    例如:

    给出序列是4, 1, 2, 3

    第一种添括号方法:

    ((4+1)+(2+3))=((5)+(5))=(10)

    有三个中间和是5510,它们之和为:5+5+10=20

    第二种添括号方法

    (4+((1+2)+3))=(4+((3)+3))=(4+(6))=(10)

    中间和是3610,它们之和为19

    题目描述

    现在要添上n-1对括号,加法运算依括号顺序进行,得到n-1个中间和,求出使中间和之和最小的添括号方法。

    输入输出格式

    输入格式:

    共两行。 第一行,为整数n。(1< =n< =20) 第二行,为a(1),a(2),...,a(n)n个正整数,每个数字不超过100

    输出格式:

    输出3行。 第一行,为添加括号的方法。 第二行,为最终的中间和之和。 第三行,为n-1个中间和,按照从里到外,从左到右的顺序输出。

    输入输出样例

    输入样例#1:

    4
    4 1 2 3
    

    输出样例#1:

    (4+((1+2)+3))
    19
    3 6 10
    

    说明

    范围在题目上有说明。

    题解

    记忆化搜索

    dp[i][j]表示n个数以i为开头j为结尾的子串的答案

    建立一个结构体来定义dp[][],其中:

    1. value表示当前区间的中间值总和,如样例中dp[1][n].value19
    2. sum表示当前区间的数的和,用来维护上一层递归的value
    3. program表示当前区间的加+方案,是string
    4. midsum表示当前区间取过的中间值,具体使用方法后面讲

    记忆化部分不再赘述,要加的一定要加不然会TLE

    设当前枚举到了[i, k]和[k + 1, j]两个区间

    1. 新的区间和dp[i][j].sum = dp[i][k].sum + dp[k + 1][j].sum

    2. 得到的中间值总和为左右两区间中间值总和的和加上新产生的区间和,即dp[i][j].value = dp[i][k].value + dp[k + 1][j].value + dp[i][j].sum, 更新条件为新值小于等于原值 (此处要注意,没有等于会WA两个点,目前原因我分析出来是洛谷没开Special Judge······)

    3. programmidsum直接string+运算就可以了

    输出答案时,programvalue正常输出,midsumstringstream处理后再输出,如果不会点这里

    代码

    #include <bits/stdc++.h>
    using namespace std;
    #define MERGE(str1, str2) string("(") + str1 + "+" + str2 + ")"
    struct number {
      int value, sum;
      string program, midsum;
      number() {
        value = sum = 0;
      }
    } dp[30][30], ans;
    int n, arr[30];
    inline number Dfs(const int &left, const int &right) {
      register number ret;
      if (dp[left][right].value) return dp[left][right];
      if (left == right) {
        ret.sum = arr[left];
        register char tmp[10];
        sprintf(tmp, "%d", arr[left]);
        ret.program = string(tmp);
        return dp[left][right] = ret;
      }
      register number tmp1, tmp2;
      ret.value = 10000;
      for (register int i(left); i < right; ++i) {
        tmp1 = Dfs(left, i);
        tmp2 = Dfs(i + 1, right);
        if (tmp1.sum + tmp2.sum + tmp1.value + tmp2.value <= ret.value) {
          ret.value = tmp1.value + tmp2.value + tmp1.sum + tmp2.sum;
          ret.sum = tmp1.sum + tmp2.sum;
          ret.program = MERGE(tmp1.program, tmp2.program);
          register char tmp[10];
          sprintf(tmp, "%d", ret.sum);
          ret.midsum = tmp1.midsum + string(" ") + tmp2.midsum + string(" ") + tmp;
        }
      }
      return dp[left][right] = ret;
    }
    int sums[30]; 
    int main(int argc, char **argv) {
      scanf("%d", &n);
      for (register int i(1); i <= n; ++i) scanf("%d", &arr[i]);
      ans = Dfs(1, n);
      register stringstream ss;
      ss << ans.midsum;
      for (register int i(0); i < n - 1; ++i) ss >> sums[i];
      cout << ans.program << endl << ans.value << endl;
      for (register int j(0); j < n - 1; ++j) cout << sums[j] << " ";
      return 0; 
    }
    

    其他

    LIPI让我帮他做。。。

    我都不相信我出了DP题

  • 相关阅读:
    杂货铺
    oracle修改已存在数据的字段类型
    使用python读取配置文件并从mysql数据库中获取数据进行传参(基于Httprunner)
    HttpRunner完整笔记(从搭建到应用)
    使用jmeter发送put请求的三种方式
    电脑同时安装了python2和python3后,随意切换版本并使用pip安装
    python+request+HTMLTestRunner+unittest接口自动化测试框架
    redis简介
    spring cloud gateway之服务注册与发现
    spring cloud gateway 之限流篇
  • 原文地址:https://www.cnblogs.com/forth/p/9534945.html
Copyright © 2020-2023  润新知