跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • [美国微软] 区间 DP,有意思
未分類
26 11 月 2020

[美国微软] 区间 DP,有意思

[美国微软] 区间 DP,有意思

資深大佬 : zzzrf 0

有一个石子归并的游戏。最开始的时候,有 n 堆石子排成一列,目标是要将所有的石子合并成一堆。合并规则如下:

  1. 每一次可以合并相邻位置的两堆石子
  2. 每次合并的代价为所合并的两堆石子的重量之和 求出最小的合并代价。

在线评测地址

样例 1:

输入: [3, 4, 3] 输出: 17 

样例 2:

输入: [4, 1, 1, 4] 输出: 18 解释:    1. 合并第二堆和第三堆 => [4, 2, 4], score = 2   2. 合并前两堆 => [6, 4],score = 8   3. 合并剩余的两堆 => [10], score = 18 

算法:区间 DP

这是一道区间 DP 问题,我们需要用区间表示状态来递推。设 s 是表示石头重量的数组,设 f[i][j]是将 s[i,…,j]的石头合并成一个所需的最少能量,那么这个最少能量按照最后一步合并的分界线可以分为以下几种情况:

1 、最后一步是 s[i]和 s[i+1,…,j]合并,此时需要的最少能量是 f[i+1][j]+sum(s[i]…s[j]),第一项是合并后者需要的能量,第二项是最后一次合并所需要的能量。s[i]自己只有一个石头,不需要合并 2 、最后一步是 s[i,i+1]和 s[i+2,…,j]合并,此时需要的最少能量是 f[i][i+1]+f[i+2][j]+sum(s[i]…s[j]),第一项是合并前两个石头需要的能量,第二项是合并后半区间石头需要的能量,最后一项是最后一次合并需要的能量; 从上面我们可以看出一个规律,f[i][j]应该是所有区间分法中前一半区间的石头合并需要的总能量加上后半区间的总能量再加上最后一次合并需要的能量

  • 求得 A 的前缀和
  • 区间长度从 2 开始枚举,
  • 根据上诉思路可得递推式
  • dp[l][r] =min(dp[l][r], dp[l][j] + dp[j + 1][r] + sum_a[r + 1] – sum_a[l])
  • 记得初始化 dp[l][r]为一个较大值
  • 结果存在 dp[0][size-1]中

复杂度分析

  • 时间复杂度 O(n^3)
    • 区间 dp 的复杂度
  • 空间复杂度 O(n^2)
    • dp 数组的大小
public class Solution {     /**      * @param A: An integer array      * @return: An integer      */     public int stoneGame(int[] A) {         int size = A.length;         if (A == null || size == 0) {             return 0;         }                  int[][] dp = new int[size][size];         int[] sum_a = new int[size + 1];         //前缀和         for (int i = 0; i < size; i++) {             sum_a[i + 1] = sum_a[i] + A[i];         }         // 长度从 2 开始即可,因为长度为 1 的时候结果是 0,dp 初始化的时候默认就是 0,没必要赋值         for (int len = 2; len <= size; len++) {             // i 枚举的是正在枚举的区间的左端点             for (int i = 0; i + len - 1 < size; i++) {                 // 正在枚举的区间左端点是 i,右端点是 i + size - 1                 int l = i, r = i + len - 1;                 // 在求最小的时候,需要初始化成一个很大的数,然后不断更新                 dp[l][r] = Integer.MAX_VALUE;                 for (int j = l; j < r; j++) {                     //递推式                     dp[l][r] = Math.min(dp[l][r], dp[l][j] + dp[j + 1][r] + sum_a[r + 1] - sum_a[l]);                 }             }         }                  return dp[0][size-1];     } } 

大佬有話說 (0)

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具