UVA 10891 Game of Sum

原创 2016年08月29日 21:57:46

题目链接:http://acm.hust.edu.cn/vjudge/problem/19461


题意:一个长度为n的序列,两个人轮流取数。每次玩家可以从左端或者右端取任意数量个数,但不能两端都取。两人都希望自己的得分尽量大。当所有数都取完后,求先手取数之和减去后手取数之和。


思路:dp[l][r]表示取区间[l,r]内的数时,先手之和减去后手之和的最大值。dp[l][r] = max( sum[l,k] - dp[k+1][r] , sum[k,r] - dp[l][k-1] )分别枚举先手从左/右端取走的个数,取最大值,记忆化搜索计算答案。


还有一种方法是参考书上的递推做法,dp[l][r]表示先手取区间[l,r]内的数获得的最大值。dp[l][r] = sum[i,j] - min( dp[l+1][r] , dp[l+2][r] , dp[l+3][r]...dp[r][r] (取左端) ,   dp[l][l] , dp[l][l+1] , dp[l][l+2] , dp[l][l+3]....dp[l][r-1] (取右端)  , 0(全部取完)     );

f[l][r] = min( dp[l+1][r] , dp[l+2][r] , dp[l+3][r]...dp[r][r]  )

g[l][r] = min( dp[l][l] , dp[l][l+1] , dp[l][l+2] , dp[l][l+3]....dp[l][r-1] )

dp[l][r] = sum - min( 0 , min(f[l][r] , g[l][r]) )

f和g存在递推式

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod 100000007

const int maxn = 109;
int n;
LL sum[maxn];
int a[maxn];
LL dp[maxn][maxn];
bool flag[maxn][maxn];

void init()
{
    sum[0] = 0;
    rep(i,1,n)
    {
        scanf("%d",&a[i]);
        sum[i] = sum[i-1] + a[i];
    }
    Clean(flag,false);
}

LL dfs( int l , int r )
{
    if ( flag[l][r] ) return dp[l][r];
    if ( l == r ) return a[l];
    if ( l > r ) return 0;
    LL ans = sum[r] - sum[l-1];
    rep(i,l,r-1)
    {
        ans = max( ans , sum[i]-sum[l-1] - dfs(i+1,r) );
        ans = max( ans , sum[r] - sum[i] - dfs(l,i) );
    }
    flag[l][r] = true;
    return dp[l][r] = ans;
}

int main()
{
    while( cin>>n )
    {
        if ( !n ) break;
        init();
        cout<<dfs(1,n)<<endl;
    }
    return 0;
}

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod 100000007

#define mp make_pair
#define fi first
#define se second

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m=(l+r)>>1
const int maxn = 109;
LL a[maxn];
LL sum[maxn];
LL dp[maxn][maxn]; //先手取最大值
LL f[maxn][maxn];
LL g[maxn][maxn];
int n;
void init()
{
    sum[0] = 0;
    rep(i,1,n)
    {
        cin>>a[i];
        sum[i] = sum[i-1] + a[i];
        dp[i][i] = a[i];
        f[i][i] = g[i][i] = inf;
    }
    rep(L,2,n)
    {
        rep(i,1,n-L+1)
        {
            int j = i + L - 1;
            f[i][j] = min( f[i+1][j] , dp[i+1][j] );
            g[i][j] = min( g[i][j-1] , dp[i][j-1] );
            dp[i][j] = sum[j] - sum[i-1] - min( 0LL , min( f[i][j] , g[i][j] ) );
        }
    }
    cout<<2*dp[1][n] - sum[n]<<endl;
}

int main()
{
    while(cin>>n)
    {
        if ( !n ) break;
        init();
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

UVA 10891 Game of Sum(记忆化搜索+博弈)

题目大意: 有一个长度为n的整数序列,A和B轮流取数字,A先取,每次只能从左端或者右端取任意数量的个数,但是不能两端都取。所有的数都被取走后游戏结束,让后统计每个人取走的数之和,作为各自得分。两个人...
  • HelloWorld10086
  • HelloWorld10086
  • 2015年02月04日 16:40
  • 493

UVA 10891 Game of Sum 总和一定的博弈,区间dp

参考:刘汝佳大白书p67-p69 整数的总和是一定的,所以一个人得分越高,另一个人的得分越低。 不管任意时刻游戏的状态都是原始序列的一段连续子序列,(因而可用区间dp) //#pragma ...
  • guognib
  • guognib
  • 2013年10月27日 10:46
  • 926

UVa 10891(记忆化搜索,递推)Game of Sum

例题28 Sum游戏(Game of Sum, UVa 10891) 有一个长度为n的整数序列, 两个游戏者A和B轮流取数, A先取。 每 次玩家只能从左端或者右端取一个数, 但不能两端都取。 所有数...
  • update7
  • update7
  • 2017年07月15日 08:04
  • 32594

区间DP(Sum游戏,uva 10891)

以前做过类似的题目,几乎就一样,所以很快就做出来了。 dp[i][j]代表对区间[i,j]先出手的最优解,那么枚举所有决策,区间dp一下就ok了。 因为先手取完后,就轮到后手取,后手取就相当于...
  • xl2015190026
  • xl2015190026
  • 2016年10月28日 01:04
  • 147

Uva 10891 sum 游戏 (及其变型) ;动态规划

题目地址http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1...
  • xu3737284
  • xu3737284
  • 2013年05月31日 11:03
  • 528

uva 10891 sum游戏(区间dp)

 给定n个数字,A和B可以从这串数字的两端任意选数字,一次只能从一端选取。并且A B都尽力使自己选择的结果为最大的,可以理解成A B每一步走的都是最优的。如果A先选择,则A B差值最大是多少...
  • u014664226
  • u014664226
  • 2015年06月20日 01:34
  • 900

sum游戏 Game of sum uva 10891 动态规划 备忘录(记忆化搜索)

题目的大意是有一个整数组成的序列,两个人轮流取数,只能从一端取一个或者多个数(这里大白书上写错了),当所有的数都被取完的时候,取到的所有的数之和为该玩家的分数,求A的分数-B的分数,两个人都是以最优的...
  • Jackwuyongxing
  • Jackwuyongxing
  • 2013年09月19日 14:41
  • 700

UVa 10891 (区间DP)

【题目链接】 http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19461【解题报告】 题目大意:给你一个N元序列,每...
  • gungnir0711
  • gungnir0711
  • 2015年11月28日 10:44
  • 122

UVA 10891【区间dp】

题意: 给定n个数字,A和B可以从这串数字的两端任意选数字,一次只能从一端选取。 并且A B每一步走的都是最优的。 在A先选择的情况下,求A,B最后差值最大是多少。 分析:无论怎么取,剩下的序...
  • u012483216
  • u012483216
  • 2016年03月23日 22:27
  • 111

[Game Engine]开源游戏框架(转至wiki)

   Agar - 一个高级图形应用程序框架,用于2D和3D游戏。Allegro - 基于 C/C++ 的游戏引擎,支持图形,声音,输入,游戏时钟,浮点,压缩文件以及G...
  • huodianyan
  • huodianyan
  • 2014年09月29日 08:17
  • 1016
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:UVA 10891 Game of Sum
举报原因:
原因补充:

(最多只允许输入30个字)