80. 石子归并
★☆ 输入文件:shizi.in
输出文件:shizi.out
简单对比时间限制:1 s 内存限制:128 MB
设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=100)。每堆沙子有一定的数量。现要将N堆沙子并成为一堆。归并的过程只能每次将相邻的两堆沙子堆成一堆(每次合并花费的代价为当前两堆沙子的总数量),这样经过N-1次归并后成为一堆,归并的总代价为每次合并花费的代价和。找出一种合理的归并方法,使总的代价最小。
例如:有3堆沙子,数量分别为13,7,8,有两种合并方案,
第一种方案:先合并1,2号堆,合并后的新堆沙子数量为20,本次合并代价为20,再拿新堆与第3堆沙子合并,合并后的沙子数量为28,本次合并代价为28,将3堆沙子合并到一起的总代价为第一次合并代价20加上第二次合并代价28,即48;
第二种方案:先合并2,3号堆,合并后的新堆沙子数量为15,本次合并代价为15,再拿新堆与第1堆沙子合并,合并后的沙子数量为28,本次合并代价为28,将3堆沙子合并到一起的总代价为第一次合并代价15加上第二次合并代价28,即43;
采用第二种方案可取得最小总代价,值为43。
【输入格式】
输入由若干行组成,第一行有一个整数,n(1≤n≤100);表示沙子堆数。第2至n+1行是每堆沙子的数量。
【输出格式】
一个整数,归并的最小代价。
【输入样例】
输入文件名:shizi.in
7
13
7
8
16
21
4
18
【输出样例】
输出文件名:shizi.out
239
水DP
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define MAX_N 100
#define INF 99999999
struct dinfo
{
int z;
int val;
};
int n;
int stone[MAX_N];
dinfo d[MAX_N][MAX_N];
dinfo dp(int s,int t)
{
int minx;
int minz;
if(d[s][t].val>=0) return d[s][t];
if(s==t)
{
d[s][s].z=0;
d[s][s].val=stone[s];
return d[s][s];
}
minx=INF;
minz=INF;
for(int k=s;k<t;k++)
{
int z=dp(s,k).z+dp(k+1,t).z+dp(s,k).val+dp(k+1,t).val;
if(minz>z)
{
minz=z;
minx=dp(s,k).val+dp(k+1,t).val;
}
}
d[s][t].val=minx;
d[s][t].z=minz;
return d[s][t];
}
int main()
{
int cost;
freopen("shizi.in","r",stdin);
freopen("shizi.out","w",stdout);
cin>>n;
for(int i=0;i<n;i++)
cin>>stone[i];
int min1,min2;
int cnt=n;
memset(d,-1,sizeof(d));
cout<<dp(0,n-1).z<<endl;
return 0;
}