石子合并(一排石头)
题目描述
有N堆石子排成一排(n<=100),现要将石子有次序地合并成一堆,规定每次只能选相邻的两堆合并成一堆,并将新的一堆的石子数,记为改次合并的得分,编一程序,由文件读入堆数n及每堆石子数(<=200);
(1)选择一种合并石子的方案,使得做n-1次合并,得分的总和最少
(2)选择一种合并石子的方案,使得做n-1次合并,得分的总和最多
输入
第一行为石子堆数n
第二行为每堆石子数,每两个数之间用一空格分隔。
输出
从第1至第n行为得分最小合并方案,第n+1行为空行,从n+2到2n+1行是得分最大的合并方案。
样例输入
4
4 5 9 4
样例输出
44
54
分析样例:
最小:
9 9 4分数为9(合并4和5)
9 13分数为13(合并4和9)
22 分数为22(合并9和13)
总分数等于9+13+22=44
最大
4 14 4分数为14(合并9和5)
4 18分数为18(合并4和14)
22分数为22(合并4和18)
总分数等于14+18+22=54
我们用
l
e
n
len
len模拟长度,
i
i
i模拟结束点,
j
j
j模拟起点,
e
n
d
end
end为结束点
最小值为
f
n
[
j
]
[
e
n
d
]
=
m
i
n
(
f
n
[
j
]
[
e
n
d
]
,
f
n
[
j
]
[
i
]
+
f
n
[
i
+
1
]
[
e
n
d
]
+
s
u
m
[
e
n
d
]
−
s
u
m
[
j
−
1
]
)
;
fn[j][end]=min(fn[j][end],fn[j][i]+fn[i+1][end]+sum[end]-sum[j-1]);
fn[j][end]=min(fn[j][end],fn[j][i]+fn[i+1][end]+sum[end]−sum[j−1]);
最大值为
f
x
[
j
]
[
e
n
d
]
=
m
a
x
(
f
x
[
j
]
[
e
n
d
]
,
f
x
[
j
]
[
i
]
+
f
x
[
i
+
1
]
[
e
n
d
]
+
s
u
m
[
e
n
d
]
−
s
u
m
[
j
−
1
]
)
;
fx[j][end]=max(fx[j][end],fx[j][i]+fx[i+1][end]+sum[end]-sum[j-1]);
fx[j][end]=max(fx[j][end],fx[j][i]+fx[i+1][end]+sum[end]−sum[j−1]);
上代码
#include<bits/stdc++.h>
#define INF 0x3f3f3f
using namespace std;
int stone[105],n,fn[205][205],fx[205][205],sum[205];
int main() {
cin>>n;
memset(sum,0,sizeof(sum));
memset(fn,INF,sizeof(fn));
memset(fx,-1,sizeof(fx));
for(int i=1; i<=n; i++) {
cin>>stone[i];
sum[i]=sum[i-1]+stone[i];//数组预处理
fn[i][i]=0;//数组预处理
fx[i][i]=0;//数组预处理
}
for(int len=1; len<=n; len++)//长度模拟
for(int j=1; j+len<=n+1; j++) {//起点模拟
int end=j+len-1;//结束点
for(int i=j; i<end; i++)//结束点模拟
fn[j][end]=min(fn[j][end],fn[j][i]+fn[i+1][end]+sum[end]-sum[j-1]),
fx[j][end]=max(fx[j][end],fx[j][i]+fx[i+1][end]+sum[end]-sum[j-1]);
}
cout<<fn[1][n]<<endl<<fx[1][n]<<endl;
return 0;
}