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. BlueDroid介绍

    目录 1. 基本结构 2. 代码区 自从Android 4.2开始,Android开始使用自己的蓝牙协议栈BlueDroid,而不是bluez BlueDroid可分为两层: - BTE: Bluet ...

  2. 那些证书相关的玩意儿(SSL,X.509,PEM,DER,CRT,CER,KEY,CSR,P12等)[zz]

    openssl dgst –sign privatekey.pem –sha1 –keyform PEM –c c:\server.pem 将文件用sha1摘要,并用privatekey.pem中的私 ...

  3. 创建数据库指定路径sql

    create database stuDB on  primary  -- 默认就属于primary文件组,可省略(/*--数据文件的具体描述--*/    name='stuDB_data',  - ...

  4. JavaScript正则表达式(三)

    正则表达式可以: •测试字符串的某个模式.例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式.这称为数据有效性验证 •替换文本.可以在文档中使用一个正则表达式 ...

  5. [LeetCode] Maximal Rectangle(good)

    Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and ...

  6. 说说怎么写clean code

    前两天参加了公司组织的一个培训,主题是“如何写出好的代码” ,刚看到这个主题,第一反应是又不知道是哪个培训机构来忽悠钱的!老大安排了,就去听听呗. 说实在的,课程内容没有什么新鲜的东西,就是讲讲如何发 ...

  7. Function---hdu5875(大连网选,区间连续求余)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5875 题意:有n个数,m个查询,每个查询有一个区间[L, R], 求ans, ans = ...

  8. documentElement和ownerDocument和ownerElement

    1.document.documentElement是指文档根节点----HTML元素 2.element.ownerDocument是指当前元素所在的文档对象----document 3.attrO ...

  9. Java学习-034-JavaWeb_003 -- JSP page 指令

    前文对 JSP 的基础知识进行了初步的讲解,此文主要讲述 JSP page 指令. page 指令用于定义页面的多种属性,例如:脚本语言.编码方式.导入的 Java 包等,page 执行的语法如下: ...

  10. Mysql-5.6.30卸载

    Mysql-5.6.30卸载 一.删除相关文件 rm  -rf  /var/lib/mysql/mysql   (删除数据文件) rm  -f  /root/.mysql_secure    (删除缺 ...