标签:就是 mem ima http jpg eof alt 题解 images
有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
输入:
有多组测试数据,输入到文件结束。 每组测试数据第一行有一个整数n,表示有n堆石子。 接下来的一行有n(0< n? <200)个数,分别表示这n堆石子的数目,用空格隔开
输出:
输出总代价的最小值,占单独的一行
样例输入:
3
1 2 3
7
13 7 8 16 21 4 18
样例输出
9
239
若最初的第L堆石子和第R堆石子被合并在一起,则说明L~R之间的每堆石子也已经被合并,这样L和R才有可能相邻。因此,在任意时刻,任意一堆石子均可以用一个闭区间[L,R]来描述,表示这堆石子是由最初的第L~R堆石子合并而成,其重量为\(\sum_{i=L}^RA_i\)。另外一定存在一个整数k(L<=k<R),在这堆石子形成之前,先有第L~K堆石子合并成一堆,第K+1~R堆石子被合并成一堆,然后这两堆石子才合并而成。
dp[i][j]:以第i个为起点,第j个为终点,所需要的最小花费
sum[i]:第1个为起点,第i个为终点的,区间和
首先把sum算出来,然后我们进行合并
举个例子来说:
有4个石头,每一个的价值分别是 1 2 3 4,他们的对应下标也是1 2 3 4,现在要求出dp[1][4]的值,也就是把这些石头合并成一堆,所需要的最小花费
那么首先 :? dp[1][1]=dp[2][2]=dp[3][3]=dp[4][4]=0
当间隔为1时,我们很容易知道:? dp[1][2]=3,dp[2][3]=5,dp[3][4]=7
当间隔为2时:
dp[1][3]=min(dp[1][1]+dp[2][3],dp[1][2]+dp[3][3])+sum(1,3)=min(5,3)+6=9
dp[2][4]=min(dp[2][2]+dp[3][4],dp[2][3]+dp[4][4])+sum(2,4)=min(7,5)+9=14
当间隔为3时:
dp[1][4]=min(dp[1][1]+dp[2][4],dp[1][2]+dp[3][4],dp[1][3]+dp[4][4])+sum(1,4)
=min(14,10,9)+10=9+10=19
经过这一个模拟的过程,我们应该已经知道了区间DP的含义,依靠一个一个小区间来逐渐推导出大区间。
所以我们的关键代码为:
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]);
#include<bits/stdc++.h>
using namespace std;
const int maxn = 210;
int a[maxn];
int sum[maxn];
int dp[maxn][maxn];
int main(void)
{
int n;
cin>>n;
memset(dp,0x3f,sizeof(dp));
for(int i = 1; i <= n; i++)
{
cin>>a[i];
dp[i][i] = 0;
sum[i] += sum[i-1]+a[i];
}
for(int len = 2; len <= n; len++) // 阶段
{
for(int l = 1; l <= n-len+1; l++) //左端点
{
int r = l+len-1; //右端点
for(int k = l; k < r; k++) //决策
{
dp[l][r] = min(dp[l][r],dp[l][k]+dp[k+1][r]);
}
dp[l][r] += sum[r]-sum[l-1];
}
}
cout<<dp[1][n]<<endl;
return 0;
}
标签:就是 mem ima http jpg eof alt 题解 images
原文地址:https://www.cnblogs.com/AC-AC/p/10468837.html