133.石子归并 2

2102 石子归并 2

 

 时间限制: 10 s
 空间限制: 256000 KB
 题目等级 : 黄金 Gold
题目描述 Description

在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

输入描述 Input Description

数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.

输出描述 Output Description

输出共2行,第1行为最小得分,第2行为最大得分.

样例输入 Sample Input

4
4 4 5 9

样例输出 Sample Output

43
54

数据范围及提示 Data Size & Hint

经典的区间动态规划。

分类标签 Tags 点此展开 

DP:因为石子绕成一个环,不是一条直线,所以dp[i][j]的含义应为从第i堆开始,合并j堆石子能得到的最优值

则易得状态转移方程为

dp1[i][j]=better(dp1[i][j],dp1[i][k]+dp1[(i+k-1)%n+1][j-k]+sum[i][j]);

代码:

 

#include

#include

using namespace std;

#include

#define INFn 101

int dpmin[INFn][INFn],dpmax[INFn][INFn],n,num[INFn],sum[INFn][INFn];

void input()

{

scanf("%d",&n);

for(int i=1;i<=n;++i)

{

scanf("%d",&num[i]);

sum[i][1]=num[i];//sum储存的是从i开始合并几堆的花费 

}

for(int j=2;j<=n;++j) 

 for(int i=1;i<=n;++i)

 sum[i][j]=sum[i%n+1][j-1]+num[i]; 

for(int i=1;i<=n;++i)

dpmin[i][1]=dpmax[i][1]=0;

}

void dp()

{

for(int j=2;j<=n;++j)//仍然要把j循环放在外面 

 for(int i=1;i<=n;++i)

 {

  dpmin[i][j]=9999999;//对当前更新的dp的预处理 

   dpmax[i][j]=0;

   for(int k=1;k<=j-1;++k)

   {

    dpmin[i][j]=min(dpmin[i][j],dpmin[i][k]+dpmin[(i+k-1)%n+1][j-k]+sum[i][j]);

    dpmax[i][j]=max(dpmax[i][j],dpmax[i][k]+dpmax[(i+k-1)%n+1][j-k]+sum[i][j]);

 

}

      }

}

int main()

{

input();

dp();

int ansmax=0,ansmin=INFn*INFn*INFn;

for(int i=1;i<=n;++i)

{

if(dpmin[i][n]

ansmin=dpmin[i][n];

if(dpmax[i][n]>ansmax)

ansmax=dpmax[i][n];

}

printf("%d %d",ansmin,ansmax);

return 0;

 

原文地址:https://www.cnblogs.com/c1299401227/p/5370681.html