当前位置:   article > 正文

区间DP_区间dp时间复杂度

区间dp时间复杂度

一.区间dp

顾名思义:区间dp就是在区间上进行动态规划,求解一段区间上的最优解。主要是通过合并小区间的 最优解进而得出整个大区间上最优解的dp算法。写法主要有记忆化搜索和递推的形式.

例题:

矩阵连乘最优

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

一个 n×m 矩阵由 n 行 m 列共 n x m 个数排列而成。两个矩阵 A 和 B 可以相乘当且仅当 A 的列数等于 B 的行数。一个 n x m 的矩阵乘以一个 m × p 的矩阵等于一个 n × p 的矩阵,运算量为 n x m x p. 矩阵乘法满足交换律,显然不同的乘法的运算量是不同的。现在给出 n 个矩阵,并输入 n+1 个数,第 i 个矩阵是 a[i-1] * a[i] .
求出最少的运算量。

考虑最后一次做乘法的位置,这会将原问题分解成两个规模较小的子问题。
需要枚举最后一次乘法的位置,转移的复杂度为O(n).
合法子问题区间为 [ i, j ]  其中 1≤ i ≤ j ≤n,故状态数为O(n^2).
总时间复杂度为O(n^3).

代码如下:(记忆化搜索的形式写法)

  1. package 线性DP;
  2. import java.util.Scanner;
  3. public class 矩阵连乘 {
  4. static int max = (int) 1e9;
  5. static int[] a = new int[200];
  6. static int[][] dp = new int[200][200];
  7. static int matrix(int l, int r) {
  8. if (dp[l][r] != max)
  9. return dp[l][r];
  10. for (int i = l; i < r; i++) {
  11. // 以i为中点分开[l,r] 那么就是左边的[l,i]先计算,右边[i+r,r]先计算,然后左右相乘计算
  12. dp[l][r] = Math.min(dp[l][r], matrix(l, i) + matrix(i + 1, r) + a[l - 1] * a[i] * a[r]);
  13. }
  14. return dp[l][r];
  15. }
  16. public static void main(String[] args) {
  17. // TODO Auto-generated method stub
  18. Scanner sc = new Scanner(System.in);
  19. int n = sc.nextInt();
  20. // 第 i 个矩阵是 a[i-1]*a[i];
  21. for (int i = 0; i <= n; i++) {
  22. a[i] = sc.nextInt();
  23. }
  24. // dp[i][j]表示(i,j)范围内矩阵乘法的最优计算量
  25. for (int i = 0; i < 200; i++) {
  26. for (int j = 0; j < 200; j++)
  27. dp[i][j] = max;
  28. }
  29. for (int i = 0; i <= n; i++)
  30. dp[i][i] = 0;
  31. }
  32. }

 括号匹配

给出一串仅由 ( ) [ ]  四个字符组成的字符串,求其中一个最长的子序列,使得其括号匹配。
空串括号匹配。
若 s 括号匹配,则(s)与 [ s ] 括号匹配。
若 s,t 括号匹配,则 st 括号匹配。

比如:

( ( ( ) ) ) =6

( ) ( ) ( ) =6

( [ ] ] )=4

直接按照题面中的意思来进行状态转移即可。
对于区间 [ l,r ] ,如果Sl=Sr,,则其可以由  [ l+1,r-1 ] 转移得到。
否则枚举中间间断点m,认为该区间是 [ l,m ] 和 [ m+1,r ] 的组合。

代码如下:

  1. package 线性DP;
  2. import java.util.Scanner;
  3. public class 括号匹配 {
  4. static char[] s;
  5. static int[][] f = new int[200][200];
  6. // 判断 第x个位置和第 y个位置是否相同
  7. static int match(int x, int y) {
  8. char x1 = s[x], y1 = s[y];
  9. if (x1 == '(' && y1 == ')') {
  10. return 1;
  11. } else if (x1 == '[' && y1 == ']') {
  12. return 1;
  13. } else {
  14. return 0;
  15. }
  16. }
  17. public static void main(String[] args) {
  18. // TODO Auto-generated method stub
  19. Scanner sc = new Scanner(System.in);
  20. int n = sc.nextInt();
  21. s = ("-" + sc.next()).toCharArray();
  22. for (int i = 1; i < n; i++) {
  23. f[i][i + 1] = match(i, i + 1);
  24. }
  25. // 枚举j-i的距离d
  26. for (int d = 2; d < n; d++) {
  27. for (int i = 1; i + d <= n; i++) {
  28. int j = i + d;
  29. f[i][j] = f[i + 1][j - 1] + match(i, j);// 判断第i位和第j位是否匹配,匹配则加一
  30. for (int k = i; k < j; k++) {
  31. f[i][j] = Math.max(f[i][j], f[i][k] + f[k + 1][j]);
  32. }
  33. }
  34. }
  35. System.out.println(f[1][n] << 1);
  36. }
  37. }

石子合并

有N堆石子排成一排(可以成环),每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子个数的和,经过N-1次合并后成为一堆。求出总的代价最小值。

如果不要求相邻两堆合并,可使用小根堆来做。

代码如下:

  1. package 线性DP;
  2. import java.util.Scanner;
  3. public class 合并石子 {
  4. static int max = (int) 1e9;
  5. static int[] a;
  6. static int[][] dp1;
  7. static int dpp(int l, int r) {
  8. if (dp1[l][r] != 0)
  9. return dp1[l][r];
  10. if (l == r)
  11. return 0;
  12. int res = max;
  13. for (int i = l; i < r; i++) {
  14. res = Math.min(res, dpp(l, i) + dpp(i + 1, r) + a[r] - a[l - 1]);
  15. }
  16. return dp1[l][r] = res;
  17. }
  18. static void plus(int n) {
  19. int[][] f = new int[200][200];
  20. for (int d = 1; d < n; d++) {
  21. for (int i = 1; i + d <= n; i++) {
  22. int j = i + d;
  23. f[i][j] = max;
  24. for (int k = i; k < j; k++) {
  25. f[i][j] = Math.min(f[i][j], f[i][k] + f[k + 1][j] + a[j] - a[i - 1]);
  26. }
  27. }
  28. }
  29. System.out.println(f[1][n]);
  30. }
  31. Scanner sc = new Scanner(System.in);
  32. int n = sc.nextInt();
  33. a = new int[n * 2 + 1];
  34. dp1 = new int[2 * n + 1][2 * n + 1];
  35. for (int i = 1; i <= n; i++) {
  36. a[i] = sc.nextInt();
  37. a[i + n] = a[i];
  38. }
  39. for (int i = 1; i <= 2 * n; i++) {
  40. a[i] = a[i - 1] + a[i];
  41. }
  42. dpp(1, 2 * n);
  43. int ans1 = max;
  44. for (int i = 1; i <= n; i++) {
  45. ans1 = Math.min(ans1, dp1[i][i + n - 1]);
  46. }
  47. System.out.println(ans1);

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/498785
推荐阅读
相关标签
  

闽ICP备14008679号