Uva 10891

经典博弈区间DP

题目链接:https://uva.onlinejudge.org/external/108/p10891.pdf

题意:

给定n个数字,A和B可以从这串数字的两端任意选数字,一次只能从一端选取。

并且A B都尽力使自己选择的结果为最大的,可以理解成A B每一步走的都是最优的。

如果A先选择,则A B差值最大是多少。

分析:

总和是一定的,所以一个得分越高,另一个人的得分越低。当前状态总是最开始的状态的一个子状态。

d(i,j): 先手取 i ~ j 最优策略下,得分最大值。

d(i,j) = sum(i,j) - min(d(i+1,j),d(i+2,j),...,d(j,j),  d(i,j-1),d(i,j-2),...,d(i,i),0)

0表示全部取完;

答案就是 d(1,n) - ( sum(1,n) - d(1,n) );

tip: sum(i,j) 可以在 O(1) 的时间内求出来。 S[i] 是 1~ i 的和,那么 sum(i,j) = S[j] - S[i-1];

#include <bits/stdc++.h>

using namespace std;

int n;
const int maxn = 100 + 10;

int S[maxn],A[maxn],d[maxn][maxn],vis[maxn][maxn];

int dp(int i,int j) {
    if(vis[i][j])
        return d[i][j];
    vis[i][j] = 1;

    int m = 0;
    for(int k=i+1;k<=j;k++)
        m = min(m,dp(k,j));
    for(int k=i;k<j;k++)
        m = min(m,dp(i,k));

    d[i][j] = S[j] - S[i-1] - m;
    return d[i][j];

}

int main()
{
    while(scanf("%d",&n)==1&&n) {
        S[0] = 0;
        for(int i=1;i<=n;i++) {
            scanf("%d",&A[i]);
            S[i] = S[i-1] + A[i];
        }
        memset(vis,0,sizeof(vis));
        printf("%d\n",2*dp(1,n)-S[n]);
    }
    return 0;
}
时间: 2024-08-25 15:22:20

Uva 10891的相关文章

uva 10891 Game of Sum (DP)

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 ca

09_Sum游戏(UVa 10891 Game of Sum)

问题来源:刘汝佳<算法竞赛入门经典--训练指南> P67 例题28: 问题描述:有一个长度为n的整数序列,两个游戏者A和B轮流取数,A先取,每次可以从左端或者右端取一个或多个数,但不能两端都取,所有数都被取完时游戏结束,然后统计每个人取走的所有数字之和作为得分,两人的策略都是使自己的得分尽可能高,并且都足够聪明,求A的得分减去B的得分的结果. 问题分析:1.设dp[i][j]表示从第i到第j的数的序列中,双方都采取最优策略的前提下,先手得分的最大值 2.若求dp[i][j],我们可以枚举从左边

UVa 10891 (博弈+DP) Game of Sum

最开始的时候思路就想错了,就不说错误的思路了. 因为这n个数的总和是一定的,所以在取数的时候不是让自己尽可能拿的最多,而是让对方尽量取得最少. 记忆化搜索: d(i, j)表示原序列中第i个元素到第j个元素构成的子序列,先手取数能够得到的最大值. sum(i, j) 表示从第i个元素到第j个元素的和 因为要让对手获得最小的分数,所以状态转移方程为: d(i, j) = sum(i, j) - min{d(枚举所有可能剩给对手的序列), 0(0代表全部取完)} s数组保存a中前i个元素的和,这样s

Uva 10891 Game of Sum(区间博弈dp)

10891 - Game of Sum Time limit: 3.000 seconds 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

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

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1832 题目大意: 两个人在玩一个游戏: 给你一行n个数字,每次只能从左端或者右端取一个或多个数字. 每个人的分值就是他们各自取得的数字之和. 假设两人都足够聪明,问先手最多能比后手多多少分. 解题思路: 其实题目意思就是先手最多能得到多少分. 设dp[l][r]是取完[l,r]的

UVA - 10891 —— Game of Sum

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19461 这道题是一道很好的线性DP的题目,这种双头都可以选取的,可以运用带有头.尾位置信息的状态 dp[i][j] := 以第i位开头,第j位结尾的子问题的最优解 dp[i][j] = max(sum(i, i+k1) - dp[i+k1+1][j], sum(i, j-k2) - dp[i][j-k2-1])  (当 i <= j,注:i+k1 <= j &

[动态规划] Sum游戏 ( Game of Sum, Uva 10891 )

抓住状态转移方程即可   :  从子序列 i j 中取最大 =  i + 从子序列i+1,j中取最大        或         j +  从子序列i,j-1中取最大 #include <algorithm> #include <cstring> #include <cstdio> using namespace std; const int maxn = 100+10; int S[maxn], A[maxn], d[maxn][maxn], vis[maxn]

UVA 10891 Game of Sum

题解: 这个题的题意挺误解人的. 每次选取的最优策略.我的理解每次从左开始.或从右开始.选取最大值(每个位置选取的最大值的位置是固定的).把剩下的序列给对方....但题意并不是这样 看了题解. 表示dp[ i ][ j ] 表示 区间 i j 先选得到的最大值. dp[ i ][ j ] = sum( j ) - sum( i - 1 ) - min( dp( i + 1, j ), dp( i + 2, j ), dp( i + 3, j )...dp( j ,j ), dp(  i , j

UVA - 10891 Game of Sum(记忆化搜索 dp)

#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; int a[100+10]; int dp[120][120]; int sum[120]; int vis[120][120]; int dfs(int f,int t) { int i,j,k; if(vis[f][t]==