Uva 10891

Uva 10891 Game of Sum
题目地址:Uva 10891
题目大意,有一个包含n(n<=100)个整数的数列,两个人轮流从中取数,每次只能从数列的某一端(左或是右)取,每次可以去出一个或多个,但不能不取,每次所取得的数的和为每人的总得分,问在两人均采取最优策略时先手能够比后手多得多少分。
题目分析:看到“最优”,以及数据范围应该能想到是n^3 DP,而本题的难点在于状态的表示。而我们可以发现对于一整个的数列两人的得分总和是一定的,因此只需要算先手的人的总得分就可以算出两者的差。用dp[i][j]表示在i~j区间内先手能得到的最大得分,而剩下的就是后手得到的,但是由于两人都是采用最优的方式,因此后手得的分也应该在dp的某个状态之中,所以转移方程为

for(int k=i;k<=i+j;k++)
	u=max(u,sum[i][i+j]-dp[i][k]);
for(int k=i+j;k>=i;k--)
	u=max(u,sum[i][i+j]-dp[k][i+j]);
dp[i][i+j]=u;

最后再算出答案
ans=dp[1][n]-(sum[n]-dp[1][n])=2*dp[1][n]-sum[n]
最后附上完整代码

#include<stdio.h>
#include<algorithm>
#include<string.h>
#define max(a,b)(a>b?a:b)
#define min(a,b)(a<b?a:b)
int dp[110][110],n,m,arr[110],sum[110][110],s[110];
int main()
{
	while(scanf("%d",&n)){
		if(n==0)break;
		memset(dp,0,sizeof(dp));
		memset(sum,0,sizeof(sum));
		for(int i=1;i<=n;i++){
			scanf("%d",&arr[i]);
			s[i]=s[i-1]+arr[i];
		}
		for(int i=1;i<=n;i++)
			for(int j=i;j<=n;j++)
				sum[i][j]=s[j]-s[i-1];
		for(int j=0;j<=n;j++){
			for(int i=1;i<=n;i++){
				if(i+j>n)break;
				int u=-0x7fffffff;
				for(int k=i;k<=i+j;k++)
					u=max(u,sum[i][i+j]-dp[i][k]);//保证此次取出的子序列尽可能大,且对手所取得依然是最优的情况 
				for(int k=i+j;k>=i;k--)
					u=max(u,sum[i][i+j]-dp[k][i+j]);
				dp[i][i+j]=u;
			}
		}
		int ans=dp[1][n]*2-sum[1][n];
		printf("%d\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值