【DP】环形石子合并

[NOI1995] 石子合并 - 洛谷

题意:

给定几堆石子,这几堆石子围成一个环,每次合并可以合并两堆相邻的石子,本次得分为这次合并的两堆石子数的和,多次合并后的得分加在一起。求最后合成一堆石子,最大得分和最小得分分别是多少?

这个题比较是比较经典的一个环处理的方法,就是把原来的数列再拷贝一份拼到数组后面,形成一个长度2n的序列。然后我们只需要考虑 合并[1,n],合并[2,n+1],合并[3,n+2],..........合并[n-1,2*n-1]的这些答案里面取一个最大和最小的即可,剩下的问题就是一个基础的石子合并的问题了。

关于合并石子,我用的记忆化,比较方便,循环推感觉不是很好考虑。(我是小菜)

注意如果l==r本次合并的代价是0,而不是a[l].

然后比较好考虑的一个性质是,合并一次[l,r]或者说本次合并[l,r]的花费等于sum_a[l][r]

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)

using namespace std;
int n;
int a[1007],sum[1007];
int dp[1007][1007],vis[1007][1007],ddp[1007][1007],vvis[1007][1007];
int dfs(int l,int r){
	if(l==r){
		return 0;
	}
	if(vis[l][r])return dp[l][r]; 
	int ans=2147483647;
	rep(i,l,r-1){
		ans=min(ans,dfs(l,i)+dfs(i+1,r)+sum[r]-sum[l-1]);
	}
	vis[l][r]=1;
	dp[l][r]=ans;
	return ans;
}
int ddfs(int l,int r){
	if(l==r){
		return 0;
	}
	if(vvis[l][r])return ddp[l][r]; 
	int ans=-1;
	rep(i,l,r-1){
		ans=max(ans,ddfs(l,i)+ddfs(i+1,r)+sum[r]-sum[l-1]);
	}
	vvis[l][r]=1;
	ddp[l][r]=ans;
	return ans;
}
int main(){

	cin>>n;
	rep(i,1,n){
		cin>>a[i];
		a[i+n]=a[i];
	}
	rep(i,1,2*n)sum[i]=sum[i-1]+a[i];	
	int ans=2147483647;
	rep(i,1,n)ans=min(ans,dfs(i,i+n-1));
	cout<<ans<<endl;
	ans=-1;
	rep(i,1,n)ans=max(ans,ddfs(i,i+n-1));
	cout<<ans;
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值