石子合并问题
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。
对于给定n堆石子,计算合并成一堆的最小得分和最大得分。
Input
输入数据的第1行是正整数n,1≤n≤100,表示有n堆石子。第二行有n个数,分别表示每堆石子的个数。
Output
输出数据有两行,第1行中的数是最小得分,第2行中的数是最大得分。
Sample Input
4
4 4 5 9
Sample Output
43
54
Hint
Source
#include <bits/stdc++.h>
using namespace std;
int n;
int p[111][111];
int a[111];
int dp[111][111];
void Init(int *a)
{
for(int i=1;i<=n;i++)
{
p[i][i]=a[i];
for(int j=i+1;j<=n;j++)
{
p[i][j]=p[i][j-1]+a[j];
}
}
}
int getMax()
{
for(int r=2;r<=n;r++)
{
for(int i=1;i<=n-r+1;i++)
{
int j=i+r-1;
dp[i][j]=dp[i+1][j]+p[i+1][j]+p[i][i];
for(int k=i+1;k<j;k++)
{
dp[i][j]=max(dp[i][j],dp[i][k]+p[i][k]+dp[k+1][j]+p[k+1][j]);
}
}
}
return dp[1][n];
}
int getMin()
{
for(int r=2;r<=n;r++)
{
for(int i=1;i<=n-r+1;i++)
{
int j=i+r-1;
dp[i][j]=dp[i+1][j]+p[i+1][j]+p[i][i];
for(int k=i+1;k<j;k++)
{
dp[i][j]=min(dp[i][j],dp[k+1][j]+dp[i][k]+p[k+1][j]+p[i][k]);
}
}
}
return dp[1][n];
}
int main()
{
cin>>n;
int cnt=n;
int minn=99999;
int maxx = 0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
while(cnt--)
{
Init(a);
int tempmax = getMax();
if(tempmax>maxx)
{
maxx=tempmax;
}
Init(a);
int tempmin = getMin();
if(tempmin<minn)
{
minn = tempmin;
}
int t=a[1];
for(int i=1;i<=n;i++)
{
a[i]=a[i+1];
}
a[n]=t;
}
cout<<minn<<endl<<maxx<<endl;
return 0;
}