UVA 10891

虽然这道题不算很难,但却是很多地方值得琢磨。
第一次遇到关于博弈论的题目一开始还是没有思路的。
后来是想到关于求最优解一般都是dp,然后往哪个方向去想,就想到了可以用区间dp的方式。
我们以dp[i][j]来表示,a先手能取得的最大值。
那么 至少每个区间i-j的总和不变,要使得dp最大,那么要另外一方最小(而且要保证另一方也是最优解)。
dp[i][j]=max(sum(i,j)-min(dp[i][k],dp[k+1][j]);
可以想到,如果要让a在这个区间内去的最小,那么要b,从i-k或者j-k+1取得最小才行,
而每个人又尽量取得最大值,那么可以认为当b先手时要最大,但这个最大的要取所有 最大值中间最小的那个,这样才能使dp[i][j]最大。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const long long INF = 0x3f3f3f3f;
using namespace std;
int n;
int a[102];
int sum[102];
int d[102][102];
int inf = INT_MIN;
//代码不难主要是思想可以很好的借鉴一下
int dp(int a,int b)
{
	int &ans = d[a][b];
	if (ans != inf)return ans;
	//if (a > b) return 0;   
	ans = sum[b]-sum[a-1];//初始化成区间长度
	up(i, a, b)
	{
		d[a][b] = max(d[a][b],sum[b] - sum[a-1] -min(dp(a, i), dp(i + 1, b)));//区间dp
	}
	return ans;
}
int main()
{
	while (cin >> n && n)
	{
		sum[0] = 0;
		upd(i, 1, n)
		{
			cin >> a[i];
			sum[i] = sum[i - 1] + a[i];//预处理一下sum值
		}
		up(i, 0, n+2)
		{
			up(j, 0, n+2)
			{
				d[i][j] = inf;
			}
		}
		int sum1 = dp(1, n);
		cout << 2 * sum1 - sum[n] << endl;//最后的和表示。
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值