题目连接:10891 - Game of Sum

题目大意:有n个数字排成一条直线,然后有两个小伙伴来玩游戏, 每个小伙伴每次可以从两端(左或右)中的任意一端取走一个或若干个数(获得价值为取走数之和), 但是他取走的方式一定要让他在游戏结束时价值尽量的高,最头疼的是两个小伙伴都很聪明,所以每一轮两人都将按照对自己最有利的方法去取数字,请你算一下在游戏结束时,先取数的人价值与后取数人价值之差(不要求绝对值)。

解题思路:这道题目想了一晚上,死憋着不看题解, 结果写出的代码有点渣,dpx[i][j]表示在当前第i个数到第j个数中先取数的人可以达到的最高价值, dpy[i][j]为后取者最高可以达到的最高值。每次根据传入的参数flag判断是该谁去石子, 通过引用返回最优解。

注意:数字可以为负数,所以标记的时候要注意, 我是重新开了个数组vis.

#include <stdio.h>
#include <string.h>
const int N = 105;
const int MAX = -0x3f3f3f3f;
int n, num[N], sum[N], dpx[N][N], dpy[N][N], vis[N][N]; void search(int a, int b, int& x, int& y, int flag) {
int &A = dpx[a][b], &B = dpy[a][b];
if (a + 1 == b)
A = num[b], B = 0; if (!vis[a][b]) {
int s, f;
A = sum[b] - sum[a], B = 0;
for (int i = a + 1; i < b; i++) {
search(i, b, s, f, !flag);
if (flag && f + sum[i] - sum[a] > A)
A = f + sum[i] - sum[a], B = s;
else if (!flag && s + sum[i] - sum[a] > A)
A = s + sum[i] - sum[a], B = f; search(a, i, s, f, !flag);
if (flag && f + sum[b] - sum[i] > A)
A = f + sum[b] - sum[i], B = s;
else if (!flag && s + sum[b] - sum[i] > A)
A = s + sum[b] - sum[i], B = f;
}
}
vis[a][b] = 1; if (flag)
x = B, y = A;
else
x = A, y = B;
} void solve() {
int s, f; memset(dpx, MAX, sizeof(dpx));
memset(dpy, MAX, sizeof(dpy));
memset(vis, 0, sizeof(vis)); search(0, n, s, f, 0);
printf("%d\n", s - f);
} int main() {
while (scanf("%d", &n) == 1 && n) {
// Read;
memset(num, 0, sizeof(num));
memset(sum, 0, sizeof(sum));
for (int i = 1; i <= n; i++) {
scanf("%d", &num[i]);
sum[i] = sum[i - 1] + num[i];
} solve();
}
return 0;
}

参考别人的题解,写了下面这个代码,因为两个小伙伴都是按照对自己最有利的方式取数字,那可以看成是一个过程,而确定区间a 到 b的最优解之后, 用sum(a, b) -  最优解就是后取数字的小伙伴可以取到的价值(只有两个人在玩,不是1拿就是2拿), 后取小伙伴的价值坑定是要尽量小自己拿到的才有可能越大。

#include <stdio.h>
#include <string.h>
const int N = 105;
const int MAX = 1 << 30;
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; } int n, dp[N][N], vis[N][N], num[N], sum[N]; void read() {
memset(dp, 0, sizeof(dp));
memset(vis, 0, sizeof(vis));
sum[0] = 0; for (int i = 1; i <= n; i++) {
scanf("%d", &num[i]);
sum[i] = sum[i - 1] + num[i];
}
} int solve(int a, int b) {
if (a >= b) return 0;
if (vis[a][b]) return dp[a][b];
int ans = -MAX, cnt = b - a;
vis[a][b] = 1;
for (int i = 1; i <= cnt; i++)
ans = max(ans, sum[b] - sum[a] - min(solve(a + i, b), solve(a, b - i)));
dp[a][b] = ans;
return ans;
} int main() {
while (scanf("%d", &n), n) {
read();
printf("%d\n", solve(0, n) * 2 - sum[n]);
}
return 0;
}

uva 10891 Game of Sum(区间dp)的更多相关文章

  1. UVA - 10891 Game of Sum 区间DP

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

  2. 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 ...

  3. 09_Sum游戏(UVa 10891 Game of Sum)

    问题来源:刘汝佳<算法竞赛入门经典--训练指南> P67 例题28: 问题描述:有一个长度为n的整数序列,两个游戏者A和B轮流取数,A先取,每次可以从左端或者右端取一个或多个数,但不能两端 ...

  4. UVa 10891 - Game of Sum 动态规划,博弈 难度: 0

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

  5. uva 10003 Cutting Sticks 【区间dp】

    题目:uva 10003 Cutting Sticks 题意:给出一根长度 l 的木棍,要截断从某些点,然后截断的花费是当前木棍的长度,求总的最小花费? 分析:典型的区间dp,事实上和石子归并是一样的 ...

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

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

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

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

  8. 28.uva 10891 Game of Sum 记忆化dp

    这题和上次的通化邀请赛的那题一样,而且还是简化版本... 那题的题解      请戳这里 ... #include<cstdio> #include<algorithm> #i ...

  9. UVa 10891 Game of Sum (DP)

    题意:给定一个长度为n的整数序列,两个人轮流从左端或者右端拿数,A先取,问最后A的得分-B的得分的结果. 析:dp[i][j] 表示序列 i~j 时先手得分的最大值,然后两种决策,要么从左端拿,要么从 ...

随机推荐

  1. php ajax提交数据 在本地可以执行,而在服务器不能执行

    1.排除是服务器的问题 把单独的ajax项目传到服务器上,可以正常返回xml数据 2.排除是项目下的限制问题 把单独的ajax放在相应的项目文件夹下,单独访问该ajax发送数据的页面,能够正常执行 3 ...

  2. bzoj 1040: [ZJOI2008]骑士 树形dp

    题目链接 1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3054  Solved: 1162[Submit][S ...

  3. (Problem 70)Totient permutation

    Euler's Totient function, φ(n) [sometimes called the phi function], is used to determine the number ...

  4. object-c 协议(Protocols)和代理(Delegation)的学习

    代理是Object-C中的一个重要机制,他可以将面向对象编程的封装特性进一步加强,不是自己负责的事情坚决不做,而是转而让对应的事情负责人(代理)去做.相反如果是自己需要负责的事情(作为别人的代理),会 ...

  5. SIM卡厂商的识别方法

    ICCID(SIM卡号码)的定义应该是: 1-6位:国际移动运营商识别码(IMSI),898600为中国移动,898601为中国联通 7-20位:移动和联通的定义是不同的.   中国移动:  第7.8 ...

  6. Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.

    2016-07-18 16:08:20 [main:53] - [WARN] Exception encountered during context initialization - cancell ...

  7. 配置管理多个ssh key

    假设需要为两台主机建立ssh key以便抓取.更新代码,主机A:111.111.111.111,主机B:222.222.222.222. 首先,用两个账户(hostA@email.com与hostB@ ...

  8. js 解析XML 在Edge浏览器下面 无法准确读到节点属性值

    js 解析XML 在Edge浏览器下面 无法准确读到节点属性值 Dom.documentElement.childNodes[j].attributes[2]  这个是大众写法 在win10的edge ...

  9. for语句及switch case用法示例

    for(初始条件:循环条件:状态改变){   循环体:执行代码} 示例一: 示例二: 示例三: 示例四: 示例五: 示例六: 示例七: switch case: 示例一: 示例二: 示例三:

  10. Canvas使用渐变之-径向渐变详解

    创建径向渐变使用 createRadialGrdient(x0,y0,r0,x1,y1,r1)​ 一共​六个参数,分别代表: 起点的圆心坐标(第一个和第二个参数), 起点园的半径(第三个参数), 终点 ...