UVA-10891 Game of Sum ,博弈区间dp,谈谈个人理解和做法

原题:https://vjudge.net/problem/UVA-10891

题意:一个长度为n的序列,两个人A,B轮流取,A先取,每次玩家只能从左端或者右端取数,所有数字取走后游戏结束,统计所取得数字之和,求A的得分减B的得分的最大值。 A,B都足够聪明因此他们都能做出最优的决策。

数据范围: 1<=n<=100.

对于这类型的题目不需要分开考虑A,B,因为A,B都做出自己最优的决策,只需要将A,B统一为先手取就行了,这会方便很多。

dp[i][j]:序列下标为i~j的序列先手方取所能得到的最优结果。( 最优结果 指 先手 - 后手 的最大值)

状态转移方程:

怎么从子状态转移到dp[i][j]呢,根据题意每次从左边或者右边取,所以应该将所有可能的情况都遍历一次

				for(int k=i;k<=j;k++){
					dp[i][j]=max(sum[i][k]-dp[k+1][j],dp[i][j]);
					dp[i][j]=max(sum[k][j]-dp[i][k-1],dp[i][j]);
				}

(sum【i】【j】 指的是 i~j的和)

#include<bits/stdc++.h>
using namespace std;
const int maxn=102;
const int minn=-0x3f3f3f3f;
int dp[maxn][maxn],num[maxn],sum[maxn][maxn];
int main(){
	int n;
	memset(sum,0,sizeof(sum));
	while(scanf("%d",&n),n){
		memset(dp,0,sizeof(dp));
		for(int i=1;i<n;i++){ //漏了这个后面dp遇到num是负数会wa 
			for(int j=i+1;j<=n;j++) dp[i][j]=minn;
		}
		for(int i=1;i<=n;i++){
			scanf("%d",num+i);
			sum[1][i]=sum[1][i-1]+num[i];
		}
		for(int i=2;i<=n;i++){
			for(int j=i;j<=n;j++){
				sum[i][j]=sum[i][j-1]+num[j];
			}
		}
		for(int i=1;i<=n;i++) dp[i][i]=num[i];
		for(int dis=1;dis<n;dis++){ // dis=distant
			for(int i=1;i<=n-dis;i++){
				int j=i+dis;
				for(int k=i;k<=j;k++){
					dp[i][j]=max(sum[i][k]-dp[k+1][j],dp[i][j]);
					dp[i][j]=max(sum[k][j]-dp[i][k-1],dp[i][j]);
				}
			}
		}
		cout<<dp[1][n]<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值