COGS 1658. [HZOI 2014] 合併石子 解題報告

合併類動歸就是要注意區間!!!
合併類動歸就是要注意區間!!!
合併類動歸就是要注意區間!!!

/*
狀態定義:dp[i][j]表示合併i到j時的最大得分 sum_stone[i][j]表示i到j石子個數 
轉移方程:dp[i][j]=max{dp[i][k]+dp[k+1][j]+sum_stone[i][j],dp[i][j]} 
邊界:max{dp[i][n+i-1]}爲答案
*/ 
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

const int maxn=500;
int sum[maxn],dp[maxn][maxn][2],st[maxn];//0 for min,1 for max
int n;

void Init(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&st[i]);
		st[i+n]=st[i];
	}
	for(int i=1;i<=n*2;i++)sum[i]=sum[i-1]+st[i];
}
void DP(){
	for(int p=1;p<n;p++)//枚舉合併區間長度 
		for(int i=1,j=i+p;(i<n*2) && (j<=n*2);i++,j=i+p){//確定區間起終點 
			dp[i][j][0]=1<<30,dp[i][j][1]=0;
			for(int k=i;k<j;k++){//枚舉斷點 
				dp[i][j][0]=min(dp[i][k][0]+dp[k+1][j][0]+sum[j]-sum[i-1],dp[i][j][0]);
				dp[i][j][1]=max(dp[i][k][1]+dp[k+1][j][1]+sum[j]-sum[i-1],dp[i][j][1]);
			}
		}
	int _max=-1,_min=1<<30;
	for(int i=1;i<=n;i++){
		_max=max(_max,dp[i][n+i-1][1]);
		_min=min(_min,dp[i][n+i-1][0]);
	}
	printf("%d\n%d",_min,_max);
}
int main()
{
	#ifndef DEBUG
		string FileName="stone2";
		freopen((FileName+".in").c_str(),"r",stdin);
		freopen((FileName+".out").c_str(),"w",stdout);
	#endif
	Init();
	DP();
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章