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
*/
posted @ 2022-08-16 17:47  new-code  阅读(31)  评论(0)    收藏  举报