This is a two player game. Initially there are n integer numbers in an array and players A and B get chance to take them alternatively. Each player can take one or more numbers from the left or right end of the array but cannot take from both ends at a time. He can take as many consecutive numbers as he wants during his time. The game ends when all numbers are taken from the array by the players. The point of each player is calculated by the summation of the numbers, which he has taken. Each player tries to achieve more points from other. If both players play optimally and player A starts the game then how much more point can player A get than player B?

Input

The input consists of a number of cases. Each case starts with a line specifying the integer n (0 < n ≤100), the number of elements in the array. After that, nnumbers are given for the game. Input is terminated by a line where n=0.

Output

For each test case, print a number, which represents the maximum difference that the first player obtained after playing this game optimally.

题目大意:给n个数,两个人轮流取数,可以从左往右或从右往左取任意多个。两个人都希望自己的取得的数的总和尽量大,都采取最优策略,问第一个人能比第二个人取得的数多多少。

思路:很容易可以想到一个$O(n^3)$的DP,用dp[i][j]代表只剩下a[i..j]的数,先手可以取得的最大值,此时后手取得的最大值为sum[i..j] - dp[i][j]。

那么状态转移方程为:dp[i][j] = max(sum[i..j], sum[i..j] - min(dp[i+1][j], dp[i+2][j]……), sum[i..j] - min(dp[i][j - 1], dp[i, j - 2])。

输出结果为2 * dp[1][n] - sum[1..n]。

代码(0.026S):

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int MAXN = ; int dp[MAXN][MAXN];
int a[MAXN], sum[MAXN];
int n; int main() {
while(scanf("%d", &n) != EOF && n) {
for(int i = ; i <= n; ++i) scanf("%d", a + i);
for(int i = ; i <= n; ++i) sum[i] = sum[i - ] + a[i];
for(int k = ; k < n; ++k) {
for(int i = ; i + k <= n; ++i) {
int j = i + k;
dp[i][j] = sum[j] - sum[i - ];
for(int p = i + ; p <= j; ++p) dp[i][j] = max(dp[i][j], sum[j] - sum[i - ] - dp[p][j]);
for(int p = j - ; p >= i; --p) dp[i][j] = max(dp[i][j], sum[j] - sum[i - ] - dp[i][p]);
}
}
printf("%d\n", * dp[][n] - sum[n]);
}
}

这个DP还有优化的余地,观察状态转移方程可以发现,dp[i][j]使用了min(dp[i+1][j], dp[i+2][j]……),而dp[i+1][j]=min(dp[i+2][j], dp[i+3][j]……),有重复的部分。

于是我们可以用l[i][j]记录max(dp[i][j], dp[i+1][j], dp[i+2][j]……),即从左往右取的后手最小值,则sum[i..j] - min(dp[i+1][j], dp[i+2][j]……)可以写成sum[i..j]-l[i+1][j]。每次更新l[i][j] = min(dp[i][j], l[i+1][j])。

同理用r[i][j]记录从右往左取的后手最小值。

至此DP优化至$O(n^2)$。

代码(0.015S):

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int MAXN = ; int dp[MAXN][MAXN];
int l[MAXN][MAXN], r[MAXN][MAXN];
int a[MAXN], sum[MAXN];
int n; int main() {
while(scanf("%d", &n) != EOF && n) {
for(int i = ; i <= n; ++i) scanf("%d", a + i);
for(int i = ; i <= n; ++i) sum[i] = sum[i - ] + a[i];
for(int k = ; k < n; ++k) {
for(int i = ; i + k <= n; ++i) {
int j = i + k;
l[i][j] = r[i][j] = dp[i][j] = sum[j] - sum[i - ];
if(i != j) {
dp[i][j] = max(dp[i][j], sum[j] - sum[i - ] - l[i + ][j]);
dp[i][j] = max(dp[i][j], sum[j] - sum[i - ] - r[i][j - ]);
l[i][j] = min(dp[i][j], l[i + ][j]);
r[i][j] = min(dp[i][j], r[i][j - ]);
}
}
}
printf("%d\n", * dp[][n] - sum[n]);
}
}

UVA 10891 Game of Sum(DP)的更多相关文章

  1. uva 10891 Game of Sum(区间dp)

    题目连接:10891 - Game of Sum 题目大意:有n个数字排成一条直线,然后有两个小伙伴来玩游戏, 每个小伙伴每次可以从两端(左或右)中的任意一端取走一个或若干个数(获得价值为取走数之和) ...

  2. UVA 10891 Game of Sum(区间DP(记忆化搜索))

    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...

  3. UVA - 10891 Game of Sum (区间dp)

    题意:AB两人分别拿一列n个数字,只能从左端或右端拿,不能同时从两端拿,可拿一个或多个,问在两人尽可能多拿的情况下,A最多比B多拿多少. 分析: 1.枚举先手拿的分界线,要么从左端拿,要么从右端拿,比 ...

  4. Max Sum (dp)

    Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. F ...

  5. URAL 1146 Maximum Sum(DP)

    Given a 2-dimensional array of positive and negative integers, find the sub-rectangle with the large ...

  6. UVA - 10891 Game of Sum 区间DP

    题目连接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19461 Game of sum Description This ...

  7. HDU 1003 Max Sum(DP)

    点我看题目 题意 : 就是让你从一个数列中找连续的数字要求他们的和最大. 思路 : 往前加然后再判断一下就行. #include <iostream> #include<stdio. ...

  8. 【UVa】Partitioning by Palindromes(dp)

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=27&page=sh ...

  9. 【noi 2.6_1481】Maximum sum(DP)

    题意:求不重叠的2段连续和的最大值. 状态定义f[i]为必选a[i]的最大连续和,mxu[i],mxv[i]分别为前缀和后缀的最大连续和. 注意:初始化f[]为0,而max值为-INF.要看好数据范围 ...

随机推荐

  1. Ubuntu 14.04 LTS 64bit 编译SDL的问题

    http://blog.csdn.net/jhting/article/details/38523945 Ubuntu 14.04 LTS 64bit 编译SDL的问题 分类: C/C++2014-0 ...

  2. java JDK8 学习笔记——第18章 自定义泛型、枚举与注释

    第十八章 自定义泛型.枚举与注释 18.1 自定义泛型 泛型定义: (1)仅定义在方法上的泛型语法 (2)用来限制泛型可用类型的extends与super关键字(3)?类型通配字符的使用 18.1.1 ...

  3. js创建元素

    js创建多条数据,插入到页面中的方法. 方法一: 执行时间大概在35ms左右. 这个就属于使用字符串拼接之后,再一次性的插入到页面中.缺点是,容易导致事件难以绑定. 方法二: 执行时间不定,最少的在8 ...

  4. php--sphinx的使用

    sphinx安装,配置,使用,分页 Sphinx简介 SQL   结构化查询语言(是一种标准,所有的关系型数据库Mysql,sqlserver,oracle) sphinx的使用两种方式: 第一种: ...

  5. Using Change Management and Change Control Within a Project

    In any project, change is inevitable whether it comes from within the project or from external sourc ...

  6. SqlServer2008R2 如何插入多条数据

    列id 为自增列 insert into Websites2values('Google','https://www.google.cm/','USA',1),('淘宝','https://www.t ...

  7. Selenium2学习-018-WebUI自动化实战实例-016-自动化脚本编写过程中的登录验证码问题

    日常的 Web 网站开发的过程中,为提升登录安全或防止用户通过脚本进行黄牛操作(宇宙最贵铁皮天朝魔都的机动车牌照竞拍中),很多网站在登录的时候,添加了验证码验证,而且验证码的实现越来越复杂,对其进行脚 ...

  8. linux压缩解压

    zip压缩文件 zip -r filename.zip filesdir zip -r filename.zip file1 file2 file3 /usr/work/school //将file1 ...

  9. LeetCode Word Break II

    原题链接在这里:https://leetcode.com/problems/word-break-ii/ 题目: Given a string s and a dictionary of words  ...

  10. java版本区别

    java版本区别 点我,点我,Eclipse几个版本号的区别(part1) 点我,点我,Eclipse几个版本号的区别(part2) 点我,点我,Eclipse几个版本号的区别(part3)