洛谷P2734 游戏 A Game

P2734 游戏 A Game

    • 27通过
    • 60提交
  • 题目提供者该用户不存在
  • 标签USACO
  • 难度普及+/提高

  讨论  题解  

最新讨论

  • 暂时没有讨论

题目背景

有如下一个双人游戏:N(2 <= N <= 100)个正整数的序列放在一个游戏平台上,游戏由玩家1开始,两人轮流从序列的任意一端取一个数,取数后该数字被去掉并累加到本玩家的得分中,当数取尽时,游戏结束。以最终得分多者为胜。

题目描述

编一个执行最优策略的程序,最优策略就是使玩家在与最好的对手对弈时,能得到的在当前情况下最大的可能的总分的策略。你的程序要始终为第二位玩家执行最优策略。

输入输出格式

输入格式:

第一行: 正整数N, 表示序列中正整数的个数。

第二行至末尾: 用空格分隔的N个正整数(大小为1-200)。

输出格式:

只有一行,用空格分隔的两个整数: 依次为玩家一和玩家二最终的得分。

输入输出样例

输入样例#1:
6 
4 7 2 9 5 2
输出样例#1:
18 11

说明

题目翻译来自NOCOW。

USACO Training Section 3.3

分析:这道题和noip2007矩阵取数游戏非常像,只需要在一个序列中取数即可,要求最大得分,很明显是dp,设f[i][j]为在序列的第i个元素到第j个元素中先手能获得的最大的分,答案显然是f[1][n],怎么转移呢?决策只有两个,要么在i取,要么在j取,那么f[i][j]和f[i+1][j]、f[i][j-1]有关系,因为状态定义的是先手,所以用当前区间的总分数-后手的分数,即f[i][j] = s[i][j] - min(f[i+1][j],f[i][j-1]),其中s是第i个元素到第j个元素的和,因为i从i+1推得,j从j-1推得,所以i逆推,j顺退.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n,s[110],f[110][110],a[110];

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        s[i] = s[i - 1] + a[i];
        f[i][i] = a[i];
    }
    for (int i = n - 1; i >= 1; i--)
        for (int j = i + 1;j <= n; j++)
            f[i][j] = s[j] - s[i - 1] - min(f[i + 1][j], f[i][j - 1]);
    printf("%d %d
", f[1][n], s[n] - f[1][n]);

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/5958039.html