UVA 10891 Game of Sum(DP)
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)的更多相关文章
- uva 10891 Game of Sum(区间dp)
题目连接:10891 - Game of Sum 题目大意:有n个数字排成一条直线,然后有两个小伙伴来玩游戏, 每个小伙伴每次可以从两端(左或右)中的任意一端取走一个或若干个数(获得价值为取走数之和) ...
- UVA 10891 Game of Sum(区间DP(记忆化搜索))
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...
- UVA - 10891 Game of Sum (区间dp)
题意:AB两人分别拿一列n个数字,只能从左端或右端拿,不能同时从两端拿,可拿一个或多个,问在两人尽可能多拿的情况下,A最多比B多拿多少. 分析: 1.枚举先手拿的分界线,要么从左端拿,要么从右端拿,比 ...
- 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 ...
- URAL 1146 Maximum Sum(DP)
Given a 2-dimensional array of positive and negative integers, find the sub-rectangle with the large ...
- UVA - 10891 Game of Sum 区间DP
题目连接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19461 Game of sum Description This ...
- HDU 1003 Max Sum(DP)
点我看题目 题意 : 就是让你从一个数列中找连续的数字要求他们的和最大. 思路 : 往前加然后再判断一下就行. #include <iostream> #include<stdio. ...
- 【UVa】Partitioning by Palindromes(dp)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=27&page=sh ...
- 【noi 2.6_1481】Maximum sum(DP)
题意:求不重叠的2段连续和的最大值. 状态定义f[i]为必选a[i]的最大连续和,mxu[i],mxv[i]分别为前缀和后缀的最大连续和. 注意:初始化f[]为0,而max值为-INF.要看好数据范围 ...
随机推荐
- html之内联元素与块状元素;
html之内联元素与块状元素 一.html之内联元素与块状元素 1.块状元素一般比较霸道,它排斥与其他元素位于同一行内.比如div,并且width与height对它起作用. 2.内联元素只能容纳文本或 ...
- MyBatis-Generator 最佳实践
为数据库中的表A生成A.java, A.java, A.xml 由于该插件生成的A.java, A.xml会带有example, 不希望生成example 数据库中的字段写有注释, 希望注释能自动生成 ...
- 记录下 QT Linux 静态编译遇到的坑
Qt下静态编译Qt,根据我的经验,如果按照Windows下那种直接拿官方sdk安装之后的文件来编译是行不通的,需要直接下载Qt的source包,目前诺基亚的源码叫做qt-everywhere-open ...
- js合计
Js合计行: 可以先循环行,然后按行获取这行带有你定义的class的td,取得这些td的 text后相加,最终赋值到这行的“合计”单元格就行了 var trslength = $("#dat ...
- oracle变量的定义和使用【转】
在程序中定义变量.常量和参数时,则必须要为它们指定PL/SQL数据类型.在编写PL/SQL程序时,可以使用标量(Scalar)类型.复合(Composite)类型.参照(Reference)类型和LO ...
- php--.prop()
.prop() 获取匹配的元素集中第一个元素的属性(property)值或设置每一个匹配元素的一个或多个属性. .prop()方法只获得第一个匹配元素的属性值 .如果元素上没有该属性,或者如果没有匹配 ...
- Java学习-029-JSON 之三 -- 模仿 cssSelector 封装读取 JSON 数据方法
前文简单介绍了如何通过 json-20141113.jar 提供的功能获取 JSON 的数据,敬请参阅:Java学习-028-JSON 之二 -- 数据读取. 了解学习过 JQuery 的朋友都知道, ...
- jquery 日历插件datepicker格式调整
<script> $(function() { $("#datepicker").datepicker({ dateFormat: "yy/mm/dd&quo ...
- Linux是怎么启动的
按下电源按钮的直到欢迎页出来之后,linux总共做的事可以分为五步来完成. 1. BIOS加电自检: 加电自检,检测硬件设备.然后按照cmos上面的顺序来搜索处在活动状态下的可以引导的设备.可以是光驱 ...
- Android-BaiduMapSDK示例的key验证失败问题
首先,Android Studio获取SHA1会出现问题. 链接:Android Studio 获取 sha1 方法如下: 根据百度的教程,使用该SHA1并不能成功验证key 在Android SDK ...