【LeetCode】1000. Minimum Cost to Merge Stones(DP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hh66__66hh/article/details/88090599

【LeetCode】1000. Minimum Cost to Merge Stones(DP)

题目

There are N piles of stones arranged in a row. The i-th pile has stones[i] stones.

A move consists of merging exactly K consecutive piles into one pile, and the cost of this move is equal to the total number of stones in these K piles.

Find the minimum cost to merge all piles of stones into one pile. If it is impossible, return -1.

Example 1:

Input: stones = [3,2,4,1], K = 2
Output: 20
Explanation: 
We start with [3, 2, 4, 1].
We merge [3, 2] for a cost of 5, and we are left with [5, 4, 1].
We merge [4, 1] for a cost of 5, and we are left with [5, 5].
We merge [5, 5] for a cost of 10, and we are left with [10].
The total cost was 20, and this is the minimum possible.

Example 2:

Input: stones = [3,2,4,1], K = 3
Output: -1
Explanation: After any merge operation, there are 2 piles left, and we can't merge anymore.  So the task is impossible.

Example 3:

Input: stones = [3,5,1,2,6], K = 3
Output: 25
Explanation: 
We start with [3, 5, 1, 2, 6].
We merge [5, 1, 2] for a cost of 8, and we are left with [3, 8, 6].
We merge [3, 8, 6] for a cost of 17, and we are left with [17].
The total cost was 25, and this is the minimum possible.

Notes:
(1)1 <= stones.length <= 30
(2)2 <= K <= 30
(3)1 <= stones[i] <= 100

题意

这题的大概意思是,一共有 n 堆石头,其中第 i 堆有stones[i] 个石头。

规定每次只能将连续的 K 堆石头合并成 1 堆,其花费为这 K 堆石头的石头总数。

要求找出将所有石头合并成 1 堆的最小花费,如果不可能合并成 1 堆,则返回 -1.

解题思路

这题应该采用dp来求解,关键在于找出dp递推公式。
假设 dp[i][j][k] 表示将第 i 到 第 j 堆石头合并成 1 堆石头的最小花费,初始的时候:

dp[i][i][0] = 0;
dp[i][i][m] = infinity;  // 1 <= m <= K.

则递推公式为:

// stonesNumber[i][j]表示第i到第j堆石头的石头总数
// i <= mid < j
dp[i][j][k] = min(dp[i][mid][1] + dp[mid+1][j][k-1] + stonesNumber[i][j])

代码

#define INF 0xFFFF

class Solution {
public:
    int ans[50][50][50];
    int prex[50];
    int mm[50][50][50];

    int dp(int l, int r, int m, int k) {
        int i, j, a, b, c;

        if((r - l + 1 - m) % (k - 1)) {
            return ans[l][r][m];
        }
        // 剪枝,否则会超时
        if(mm[l][r][m]) {
            return ans[l][r][m];
        }
        if(l == r) {
            if(m == 1) {
                ans[l][r][m] = 0;
                return ans[l][r][m];
            }
            else {
            	// 返回的是无穷大,因为1堆石头不可能分成多堆
                return ans[l][r][m];
            }
        }
        if(m == 1) {
        	// 分成k堆
            ans[l][r][m] = dp(l, r, k, k) + prex[r+1] - prex[l];
            mm[l][r][m] = 1;
            return ans[l][r][m];
        }

        for(i=l; i<r; i++) {
			//左数第一堆的左边界是l,右边界可能是l到r-1
            ans[l][r][m] = min(ans[l][r][m], dp(l, i, 1, k) + dp(i+1, r, m-1, k));
            mm[l][r][m] = 1;
        }
        return ans[l][r][m];
    }

    int mergeStones(vector<int>& stones, int K) {
        int i, j, a, len;


        len = stones.size();
        for(i=0; i<len; i++) {
            for(j=0; j<len; j++) {
                for(a=1; a<=K; a++) {
                    ans[i][j][a] = INF;
                    mm[i][j][a] = 0;
                }
            }
        }

        prex[0] = 0;
        prex[1] = stones[0];
        for(i = 2; i<=len; i++) {
            prex[i] = prex[i-1] + stones[i-1];
        }


        int ret = dp(0, len-1, 1, K);
        if(ret < INF) {
            return ret;
        }
        return -1;

    }
};

猜你喜欢

转载自blog.csdn.net/hh66__66hh/article/details/88090599