排成一条线的纸牌博弈问题

排成一条线的纸牌博弈问题

题目描述

给定一个整型数组arr,代表数值不同的纸牌排成一条线,玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿,但是每个玩家每次只能拿走最左和最右的纸牌,玩家A和玩家B绝顶聪明。请返回最后的获胜者的分数。

输入描述:

输出包括两行,第一行一个整数 n ( 1 ≤ n ≤ 5000 ) n(1 \leq n \leq 5000 ) n(1n5000),代表数组arr长度,第二行包含n个整数,第i个代表 a r r [ i ] ( 1 ≤ a r r [ i ] ≤ 1 0 5 ) arr[i]( 1 \leq arr[i] \leq 10^5 ) arr[i](1arr[i]105)

输出描述:

输出一个整数,代表最后获胜者的分数。

示例1
输入
4
1 2 100 4
输出
101
备注:

时间复杂读 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( n 2 ) O(n^2) O(n2)


题解:

设胜者的总分为 x ,败者的总分为 y,并且 x - y = diff ---- 式(1);

又两者的分数和为纸牌的总分,有 x + y = sum ---- 式(2);

式(1) 和 式(2) 联立得到 x = (sum + diff) / 2。

此题就是求最大的 diff 。

设 F[i, j] 表示 在 i-j 牌中,先拿的分数减去后拿的分数,故 F[i, j] = max{a[i] - F[i + 1, j], a[j] - F[i, j - 1]}。

代码:
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 5010;

int a[N];
int n;
int f[N][N];

int main(void) {
    scanf("%d", &n);
    int sum = 0;
    for (int i = 0; i < n; ++i) {
        scanf("%d", a + i);
        sum += a[i];
        f[i][i] = a[i];
    }
    for (int i = n - 1; i >= 0; --i) {
        for (int j = i + 1; j < n; ++j) {
            f[i][j] = max(a[i] - f[i + 1][j], a[j] - f[i][j - 1]);
        }
    }
    int diff = f[0][n - 1] > 0 ? f[0][n - 1] : -f[0][n - 1];
    printf("%d\n", (sum + diff) >> 1);
    return 0;
}
滚动数组优化:
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 5010;

int a[N];
int n;
int f[N];

int main(void) {
    scanf("%d", &n);
    int sum = 0;
    for (int i = 0; i < n; ++i) {
        scanf("%d", a + i);
        sum += a[i];
        f[i] = a[i];
    }
    for (int i = n - 1; i >= 0; --i) {
        for (int j = i + 1; j < n; ++j) {
            f[j] = max(a[i] - f[j], a[j] - f[j - 1]);
        }
    }
    int diff = f[n - 1] > 0 ? f[n - 1] : -f[n - 1];
    printf("%d\n", (sum + diff) >> 1);
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值