P1880 [NOI1995] 环形石子合并
P1880 [NOI1995] 环形石子合并
https://www.luogu.com.cn/problem/P1880
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
const int inf=0x3fffffff;
const int N=5;
//f1[i][j] 合并i~j堆石子获得最大分数
//f2[i][j] 合并i~j堆石子获得最小分数
//n 输入n堆石子 minl合并最小得分 maxl合并最大得分 num[N]每堆石子数量
int n,minl,maxl,f1[N][N],f2[N][N],num[N];
int s[N];//s[i]前缀和 前i堆石子数量
int d(int i,int j){return s[j]-s[i-1];}//前缀和 求从i~j石子的个数
int main(){
scanf("%d",&n);//输入石子堆数
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);//输入每一堆的数量
num[i+n]=num[i];//输入i+n堆的数量 处理环需要存放2份数据 1 2 3 4 5 1 2 3 4 5
}
for(int i=1;i<=n+n;i++){//1-2n所有石子数量前缀和 环转链可以遍历所有情况 1 2 3 4 5 1 2 3 4 5
s[i]=s[i-1]+num[i];//每个区间的
}
for(int p=1;p<n;p++){//枚举区间长度 p= 1~n 由于算最大区间,需要使用到较小区间,所有需要每件所有区间长度
for(int i=1,j=i+p;(j<n+n)&&(i<n+n);i++,j=i+p){//合并 i~j =p 的区间
f2[i][j]=inf;//求最小得分 默认给最大
for(int k=i;k<j;k++){//在k堆石子处分成两部分
//动态转移方程 合并i~k的最大得分:R1 +合并k+1~j的最大得分R2 +合并前面2堆 R1和R2得分 d(i,j) --合并所有石子数
f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+d(i,j));
//动态转移方程 合并i~k的最少得分:R1 +合并k+1~j的最少得分R2 +合并前面2堆 R1和R2得分 d(i,j) --合并所有石子数
f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j]+d(i,j));
}
}
}
minl=inf;
for(int i=1;i<=n;i++){
maxl=max(maxl,f1[i][i+n-1]);//遍历1~n ,2~ n+1 3~ n+2,n~2n 最大得分maxl 打擂台
minl=min(minl,f2[i][i+n-1]);//遍历1~n ,2~ n+1 3~ n+2,n~2n 最小得分minl 打擂台
}
printf("%d\n%d",minl,maxl);
return 0;
}
/*
https://www.luogu.com.cn/problem/P1880
4
4 5 9 4
*/
作者:newcode 更多资源请关注纽扣编程微信公众号

从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习

浙公网安备 33010602011771号