leetcode 1000. Minimum Cost to Merge Stones

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

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.

解析:又是一道合并的问题。从题目可以看出,每次合并减少K-1堆石头,如果想要合并成功,(len - 1) % (K-1) == 0,否则就不能成功合并;

从题目中可以知道[0,len-1]要合并成k堆,最后合并成一堆,那么dp[0][len-1][k] = min(dp[0][len-1][k] , dp[0][j][1]+dp[j+1][len-1][k-1])。我之前的想法是,对于每个分割点j,[0,j]可以合并成m堆,[j+1 , len-1]就合并成k-m堆 。对于一段区间而言,能合并的堆数是可以求的,比如区间[i,j],能合并的堆数为 (j-i+1-1)%(K-1)+1 , (j-i+1-1)%(K-1)+1+K-1,(j-i+1-1)%(K-1)+1+K-1+K-1.......除了第一种以外说明其中有可以合并的堆没有合并,既然不合并,那么就可以转换成分割点前移的情况。比如[1,2,3,4,5,6],K为3当分割点为4时不合并,可以转换成分割点为1,2,3的情况,这些情况之前已经遍历过了.所以可以将状态设为[i,j]区间合并所有能合并后剩下的堆数

所以dp[i][j] = min(dp[i][j] , dp[i][k]+dp[k+1][j]) 这里还有一种情况需要考虑如果[i,k]合并剩下的堆数+[k+1,j]合并剩下的堆数>K时是不可以的,因为这样子[i,j]中还有可以合并但是没有合并的堆数.

当[i,k]合并剩下的堆数+[k+1,j]合并剩下的堆数==K时,需要再次合并为1堆,加上[i,j]区间内所有的石头数。

class Solution {
public:
    int mergeStones(vector<int>& stones, int K) 
    {
        int len = stones.size() ;
        if((len - 1) % (K - 1)) return -1 ;
        
        vector<vector<int>> dp(len + 1 , vector<int>(len , 0)) ;
        vector<int> prevsum(len + 1 , 0);
        for(int i = 0 ; i < len ; i++) prevsum[i+1] = prevsum[i]+stones[i] ;
        
        for(int l = K ; l <= len ; l++)
            for(int i = 0 ; i + l <= len ; i++)
            {
                dp[l][i] = INT_MAX ;
                for(int l1 = 1 ; l1 < l ; l1++)
                    if((l1 - 1) % (K - 1) + 1 + (l - l1 - 1)%(K - 1) + 1 <= K) dp[l][i] = min(dp[l][i] , dp[l1][i] + dp[l - l1][l1+i]) ;
                
                if((l - 1) % (K - 1) == 0) dp[l][i] += prevsum[i+l] - prevsum[i] ;
                //cout<<l<<" "<<i<<" "<<dp[l][i]<<endl;
            }
        return dp[len][0] ;
    }
};

  

 

 

posted on 2020-04-07 13:26  景行cmy  阅读(114)  评论(0)    收藏  举报