石子合并(弱化版)
题目描述
设有 \(N(N \le 300)\) 堆石子排成一排,其编号为 \(1,2,3,\cdots,N\)。每堆石子有一定的质量 \(m_i(m_i \le 1000)\)。现在要将这 \(N\) 堆石子合并成为一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻。合并时由于选择的顺序不同,合并的总代价也不相同。试找出一种合理的方法,使总的代价最小,并输出最小代价。
输入格式
第一行,一个整数 \(N\)。
第二行,\(N\) 个整数 \(m_i\)。
输出格式
输出文件仅一个整数,也就是最小代价。
样例
样例输入 #1
4
2 5 3 1
样例输出 #1
22
解析
令\(dp[i][j]\)表示区间\([i,j]\)的最小价值。
不妨从终点考虑问题,即结果为两个子区间合并的最小值再加上合并需要的代价即可。
枚举两个子区间,即枚举这个区间的中间点\(k\),使这个区间被分为\([i,k]\)和\([k+1,j]\)两个区间,取一遍最小值加上合并的即为当前区间所求。
至于合并的代价,用前缀和即可。
所以$$dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])$$
代码
#include<bits/stdc++.h>
using namespace std;
int dp[310][310],a[310],sum[310];
int main()
{
int n;
cin>>n;
memset(dp,0x3f,sizeof(dp));//初始化1,因为是求最小代价,所以初始化设为很大的一个数,为了后面更新。
for(int i=1;i<=n;i++)
{
cin >> a[i];
sum[i]=sum[i-1]+a[i];
dp[i][i]=0;//初始化2,他自己本身的代价为0。
}
for(int len=2;len<=n;len++)
{
for(int i=1;i<=n-len+1;i++)
{
int j=i+len-1;
for(int k=i;k<j;k++)
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
}
}
}
cout<<dp[1][n];
}
标签:弱化,int,sum,石子,合并,代价,dp
From: https://www.cnblogs.com/momotrace/p/p1775.html