P1880 [NOI1995]石子合并【区间DP】

题目描述

在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1: 

4
4 5 9 4

输出样例#1:

43
54
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=310;
 4 const int INF=0x3f3f3f3f;
 5 int dp[MAXN][MAXN],sum[MAXN],ans[MAXN],DP[MAXN][MAXN];
 6 int jian(int i,int j){ return sum[j]-sum[i-1]; }//i-1是因为前缀和要减去前一个而不是当前的那个。
 7 int main()
 8 {
 9     int n;
10     scanf("%d",&n);
11     for (int i = 1; i <=n ; ++i) {
12         scanf("%d",&ans[i]);
13     }
14     for (int i = 1; i <=n+n ; ++i) {//拆开环,双向
15         ans[i+n]=ans[i];
16         sum[i]=ans[i]+sum[i-1];//前缀和
17     }
18     memset(dp,0, sizeof(dp));
19     for (int l = 1; l <n ; ++l) {// 步长 ,l==1时,步长为二
20         for (int i = 1,j=i+l; (j<n+n)&&(i<n+n) ; ++i,j=i+l) {
21             DP[i][j]=INF;
22             for (int k = i; k <j ; ++k) {//每一步当中的分割点
23                 dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+jian(i,j));//l-r的最大值
24                 DP[i][j]=min(DP[i][j],DP[i][k]+DP[k+1][j]+jian(i,j));
25             }
26         }
27     }
28     int MAX=0,MIN=INF;
29     for(int i=1;i<=n;i++)
30     {
31         MAX=max(MAX,dp[i][i+n-1]);
32         MIN=min(MIN,DP[i][i+n-1]);
33     }
34     printf("%d
%d
",MIN,MAX);
35     return 0;
36 }
View Code
原文地址:https://www.cnblogs.com/-xiangyang/p/9387813.html