题目要求:
(1)第一个模型:一行排列且相邻合并
有n堆石子A1,A2,...,An形成一行,每堆石头个数记为ai(1<=i<=n),相邻两堆可合并,合并的分值为新堆的
石子数。求合并为一堆的最低得分和最高得分。
(2)第二个模型:一圈排列且相邻合并
有n堆石子A1,A2,...,An形成首位相连的一个环形,An和A1相邻,每堆石头个数记为ai(1<=i<=n),相邻两堆
可合并,合并的分值为新堆的石子数。求合并为一堆的最低得分和最高得分。
输入:
给定 n,a1~an
输出:
分别输入a第一模型和第二模型的最小值和最大值
刚开始的时候根本没察觉到就是矩阵连乘的经典问题,唉~做题太少了,付出的太少了~
(第一模型):
按照矩阵连乘的模式:令f(i,j)表示为合并ai~aj所得的最小得分,则有
f(i,j)=0 , i==j
f(i,j)=min{f(i,k)+f(k+1,j)|i<=k<j}+sum(a[i]+......+a[j])
同理可得最大值
(第二模型):
第二模型可以转化为第一模型
可以看成切断某个位置后形成的第一模型,由于是圆形的,所以可以有n种切割方法,求n种方法中的最大最小值。
注意转移方程的顺序:(按斜对角线填充)
l:2~n
i:1~n-l+1;
j=i+l-1;
例如:
#include <iostream>
using namespace std;
#define N 1000
#define inf 99999999
int n,a[N],sum[N];
int dp[N][N];
void next() //求下一数列
{
int temp=a[1];
for(int i=2;i<=n;i++)
{
a[i-1]=a[i];
}
a[n]=temp;
sum[0]=sum[1]=0;
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
}
}
int matrix_chain_min() //求最小值
{
for(int i=1;i<=n;i++)
dp[i][i]=0;
for(int l=2;l<=n;l++)
{
for(int i=1;i<=n-l+1;i++)
{
int j=i+l-1;
dp[i][j]=inf;
for(int k=i;k<j;k++)
{
int min=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
if(dp[i][j]>min)
dp[i][j]=min;
}
}
}
return dp[1][n];
}
int matrix_chain_max() //求最大值
{
for(int i=1;i<=n;i++)
dp[i][i]=0;
for(int l=2;l<=n;l++)
{
for(int i=1;i<=n-l+1;i++)
{
int j=i+l-1;
dp[i][j]=0;
for(int k=i;k<j;k++)
{
int max=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
if(dp[i][j]<max)
dp[i][j]=max;
}
}
}
return dp[1][n];
}
int main()
{
cin>>n;
sum[0]=sum[1]=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
int max=matrix_chain_max(),min=matrix_chain_min();
cout<<min<<" "<<max<<endl;
for(int k=0;k<n-1;k++)
{
next();
int p=matrix_chain_max();
int q=matrix_chain_min();
if(p>max) max=p;
if(q<min) min=q;
}
cout<<min<<" "<<max<<endl;
return 0;
}