简单的区间dp,dp[i][j]表示从i~j区间所得的最大最小分。
以最大得分为例:
1.首先初始化dp函数,为0;
2.计算出前缀和;
3.枚举区间长度len;
4.枚举起始区间的位置j;
5.因为将新的一堆石子的数量记为得分数,以dp[1][2]为例,
第一堆第二堆石子合并后数量为a[1]+a[2],即sum[2]-sum[0],
这是得分数,dp[1][2] = dp[1][1]+dp[2][2]+sum[2]-sum[0];
所以dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])
含义是第i~k堆的石子加上k+1~j堆的石子,在合并k和k+1堆时
分数是第i~j堆石子数量的总和
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int main()
{
int dp[101][101],sum[101],a[101],n;
while(~scanf("%d",&n))
{
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
for(int i = 1 ; i <= n ; i++)
{
scanf("%d",&a[i]);
sum[i] = sum[i-1]+a[i];
}
for(int len = 2 ; len <= n ; len++)//枚举区间长度
{
for(int i = 1 ; i <=n ;i++)
{
int j = i+len-1;
if(j>n) continue;
for(int k = i ; k < j ;k++)
{
dp[i][j] = max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
}
}
}
int a1 = dp[1][n];
for(int i = 0 ; i <= n ; i++)
for(int j = 0 ; j <= n ; j++)
dp[i][j] = 1e8;
for(int i = 0 ;i<=n ;i++)
dp[i][i] = 0;
for(int len = 2 ; len <= n ; len++)
{
for(int i = 1 ; i <=n ;i++)
{
int j = i+len-1;
if(j>n) continue;
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]);
}
}
}
int a2 = dp[1][n];
cout<<a2<<" "<<a1<<endl;
}
return 0;
}