【区间dp】合并石头(连续k个)

传送门

设 f[l][r][k] 为 l, r, 里分成 k 段的代价。

  • 以长度为阶段。
  • f[l][r][k] = min(f[l][r][k], f[l][mid][k – 1] + f[mid + 1][r][1])
  • 答案就是f[l][r][1]

每个k只用从k-1和1转移,因为对于任何k-n,n,一定可以分解为k-1,1,1,1,..1;所以对于前面的状态都是被考虑过的,不用再重复考虑。

#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
    int f[63][63][63], sum[33];
    int mergeStones(vector<int>& stones, int K) {
        memset(f, 0x3f, sizeof f);
        memset(sum, 0, sizeof sum);
        int s = stones.size();
        for(int i = 1; i <= s; i++) sum[i] = sum[i - 1] + stones[i - 1];
        while(s >= K)
        {
            s -= K;
            s++;
        }
        if(s > 1) return -1;
        s = stones.size();
        for(int i = 1; i <= s; i++) f[i][i][1] = 0;
        for(int len = 2; len <= s; len++)
        {
            for(int l = 1; l <= s - len + 1; l++)
            {
                int r = l + len - 1;
                for(int k = 2; k <= K; k++)
                {    
                    for(int j = l; j < r; j++)
                    {
                        f[l][r][k]=min(f[l][r][k],f[l][j][k-1]+f[j+1][r][1]);
                    }
                }
                f[l][r][1] = min(f[l][r][1], f[l][r][K] + sum[r] - sum[l - 1]);
            }
        }
        return f[1][s][1];
    }
};

发表评论

邮箱地址不会被公开。 必填项已用*标注