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.
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.
解析:又是一道合并的问题。从题目可以看出,每次合并减少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] ;
}
};

浙公网安备 33010602011771号