您的位置:首页 > 其它

石子合并

2018-01-20 16:11 465 查看
P1880 [NOI1995]石子合并

题目描述

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

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

状态转移方程的定义: dp( l , r ) 的含义是合并l - r这段区间的石子所能获得的最大值,那么,合并第i颗石子的最大值就是左边的加右边的

环形的……

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN = 205;
int Max[MAXN][MAXN],Min[MAXN][MAXN];
int sum[205];
int dp(int l,int r) {
if(Max[l][r]) {
return Max[l][r];
}
if(l == r) {
return 0;
}
int t1 = 0;
for(int i = l; i < r; i++) {
t1 = max(dp(l, i) + dp(i + 1, r) + sum[r] - sum[l - 1],t1);     //为什么要加上 sum[r] - sum[l - 1]
//因为合并一次,要消耗的值就是l - r的石子中数之和
}
return Max[l][r] = t1;
}
int dp2(int l ,int r) {
if(Min[l][r]) {
return Min[l][r];
}
if(l == r) {
return Min[l][r] = 0;
}
int t1 = 999999;
for(int i = l; i < r; i++) {
t1 = min(dp2(l, i) + dp2(i + 1, r) + sum[r] - sum[l - 1],t1);
}
return Min[l][r] = t1;
}
int main() {
int n;
cin>>n;
for(int i = 1; i<=n; i++) {
cin>>sum[i];
sum[i+n] = sum[i];
}
for(int i = 1; i <= 2*n; i++) sum[i] += sum[i - 1];
dp2(1,2*n);
dp(1,2*n);
int minn = 999999,maxn = 0;
for(int i = 1; i<=n; i++) {
minn = min(Min[i][n+i-1],minn);
}
cout<<minn<<endl;
for(int i = 1; i<=n; i++) {
maxn = max(Max[i][n+i-1],maxn);
}
cout<<maxn;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划