每日一题之 hiho1338 A Game

描述
Little Hi and Little Ho are playing a game. There is an integer array in front of them. They take turns (Little Ho goes first) to select a number from either the beginning or the end of the array. The number will be added to the selecter’s score and then be removed from the array.

Given the array what is the maximum score Little Ho can get? Note that Little Hi is smart and he always uses the optimal strategy.

输入
The first line contains an integer N denoting the length of the array. (1 ≤ N ≤ 1000)

The second line contains N integers A1, A2, … AN, denoting the array. (-1000 ≤ Ai ≤ 1000)

输出
Output the maximum score Little Ho can get.

样例输入
4
-1 0 100 2
样例输出
99

题意:

两个人玩游戏,给一组数,每个人每次可以拿掉这组数的开头的那个数或者结尾的那个数。拿掉的数当做自己所获得的分数。两个人都会采用最优的策略,问第一个人能获得的最大分数。

思路:

一开始没想到是区间dp,后来看了讨论区,发现自己还是没想到点子上。
区间dp
其实本题是一道非常经典的动态规划题目。

由于每次只能从数组首/尾拿走一个数,所以小Hi和小Ho在任何时候面对的残局都只可能是一段连续的子数组A[i..j]。我们不妨用f[i][j]表示当面对A[i..j],先手最多能获得的得分。

如果我们能计算出所有f[i][j]的值,那么显然f[1][n]就是最终答案。

其中i = j的情况f[i]j的值是很容易计算的:f[i][j]=A[i]。因为只剩下A[i]一个数,先手只能拿走A[i]。

扫描二维码关注公众号,回复: 2581647 查看本文章

对于i < j的情况,先手P需要决策是拿走A[i]还是拿走A[j]?

如果拿走A[i],那么对手Q面对的是A[i+1 .. j],Q最多能获得的得分是f[i+1][j]。而且Q一定会按照得到f[i+1][j]这个得分的方式进行决策。所以先手P最大得分是sum(A[i .. j]) - f[i+1][j]。(A[i][j]的分数和减去P的得分)

同理如果拿走A[j],先手P最大得分会是sum(A[i .. j]) - f[i][j-1]。

由于此时先手P可以二选一,所以f[i][j] = max{ sum(A[i .. j]) - f[i+1][j], sum(A[i .. j]) - f[i][j-1] } = sum(A[i .. j]) - min(f[i+1][j], f[i][j-1])。

注意sum(A[i .. j])可以通过预处理出前缀和再O(1)计算得出

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

using namespace std;

const int maxn = 1e3 + 5;

int dp[maxn][maxn];
int sum[maxn];
int A[maxn];


int main()
{
    int n;
    cin >> n;
    memset(dp,0,sizeof(dp));
    for (int i = 1; i <= n; ++i) {
        cin >> A[i];

        sum[i] = sum[i-1] + A[i];
        dp[i][i] = A[i];
    }

    for (int len = 2; len <= n; ++len) { //区间长度 2~n
        for (int l = 1; l <= n; ++l) { //区间起点
            int r = l+len-1;  //区间终点
            if (r > n) break;
            for (int k = l; k < r; ++k) {//枚举分割点
                dp[k][r] = sum[r] - sum[k-1] - min(dp[k+1][r],dp[k][r-1]);
            }
        }
    }
    cout << dp[1][n] << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/u014046022/article/details/81225859