计蒜客-合并石子 区间dp

题目链接 https://www.jisuanke.com/course/709/36587

题解: LeetCode里面有个戳气球的题和这个类似,用区间dp来解。

由于n堆(n>=2)石子合并,最终一定会有个只剩2堆石子的中间状态,这个状态就是突破口。

最终的2堆石子一定是在原来的石子里面连续的,可以用dp[i][j]表示区间i..j的石子合并后最小的体力消耗,

n堆石子消耗的最小体力为dp[1][n],先将石子合并来只剩2堆,只需要枚举2堆石子的边界即可,最后再将2堆石子合并为1堆。所以状态转移方程为dp[i][j] = min(dp[i][k]+dp[k+1][j]+sum[i][j]) (i<=k<j),sum[i][j]表示i..j区间的石子重量和

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 0x3fffff
using namespace std;
int n;
int a[100];
int dp[100][100];
int Count[100];// 统计区间和 

int main() {
	scanf("%d",&n);
	for(int i = 1;i <= n;i++) {
		scanf("%d",&a[i]);
		Count[i] = Count[i-1] + a[i];
	//	printf("%d ",Count[i]);			
	}		
//	printf("\n");
	// 区间dp
	// 枚举区间长度
	for(int len = 2;len <= n;len++)  
		// 区间起点
		for(int i = 1;i <= n;i++)  {
			if(i+len-1>n) break;
			//dp[i][i+len-1] = ;
			// 最后剩2堆石子,枚举左边那堆石子的右边界 
			int t = MAXN;
			for(int k = i;k < i+len-1;k++) {
				t = min(t,dp[i][k]+dp[k+1][i+len-1]+Count[i+len-1]-Count[i-1]);
			}
			dp[i][i+len-1] = t;
		//	printf("dp[%d][%d]=%d\n",i,i+len-1,t);
		}
	
	printf("%d\n",dp[1][n]);
	
	
	return 0;
}

 

没有更多推荐了,返回首页