P1775 石子合并(弱化版)

石子合并(弱化版)

题目描述

设有 N ( N ≤ 300 ) N(N \le 300) N(N300) 堆石子排成一排,其编号为 1 , 2 , 3 , ⋯   , N 1,2,3,\cdots,N 1,2,3,,N。每堆石子有一定的质量 m i   ( m i ≤ 1000 ) m_i\ (m_i \le 1000) mi (mi1000)。现在要将这 N N N 堆石子合并成为一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻。合并时由于选择的顺序不同,合并的总代价也不相同。试找出一种合理的方法,使总的代价最小,并输出最小代价。

输入格式

第一行,一个整数 N N N

第二行, N N N 个整数 m i m_i mi

输出格式

输出文件仅一个整数,也就是最小代价。

样例 #1

样例输入 #1

4
2 5 3 1

样例输出 #1

22

分析

区间dp,为了尽可能优化,还可以使用前缀和优化,注意枚举顺序

代码

#include
using namespace std;
#define int long long
const int MAXN=305;
int n,m[MAXN],sm[MAXN];
int dp[MAXN][MAXN];
signed main()
{
	cin>>n;memset(dp,0x3f3f,sizeof(dp));
	for(int i=1;i<=n;i++) cin>>m[i],sm[i]=sm[i-1]+m[i];
	
	for(int len=1;len<=n;len++)
		for(int l=1;l<=n-len+1;l++){
			int r=l+len-1;
			int ans=0x3f3f3f;
			if(l==r) dp[l][r]=0;
			else {
				for(int k=l;k<r;k++) ans=min(ans,dp[l][k]+dp[k+1][r]+sm[r]-sm[l-1]);
				dp[l][r]=ans;	
			}
		}
	cout<<dp[1][n];
	return 0;
}
}

分析

区间dp应先枚举长度,再枚举左端点,这样才能保证正确枚举

l,r,len的关系

r − l + 1 = l e n r-l+1=len rl+1=len

int r=l+len-1;

所以记得减1

你可能感兴趣的:(算法,动态规划,KISS)