首页 > 试题广场 >

双人数字游戏

[编程题]双人数字游戏
  • 热度指数:535 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
游戏规则如下
- 在棋盘上有N个数字(A1~AN)从左到右排列成一行
- A,B两个玩家轮流进行游戏,第一回合A玩家行动,第二回合B玩家行动,依次行动直到游戏结束
- 每回合玩家可以选择拿走棋盘上最左边或者最右边的一个数字,其余的都不能拿
- 拿走的数字依次从左到右排列在自己面前
- 棋盘上所有数字被拿走后游戏结束
- 最优策略的说明:在任意局面下,玩家如果取左边的数字或者取右边的数字,最终最优得分都一样,那么只能取左边的数字

当所有数字都被拿走后,A,B两个玩家面前都各有一个数列。
假设A玩家面前数字从左到右为 X1,X2,X3...XM,则他的最终得分Sa计算方式如下(B玩家的得分计算Sb也类似,不赘述):
Sa = abs(X1-0) + abs(X2-X1) + abs(X3-X2) + ... + abs(XM - X(M-1))


请计算在以上的规则下,如果两个玩家都想拿到尽量多的分数,用最优策略进行游戏,计算两个人的最终得分。


输入描述:
第一行一个数字 N, 一半的测试用例 (0 < N <= 50),一半的测试用例 (0 < N <= 1000)
第二行N个数字 Ai ( 0 <= Ai <= 50)


输出描述:
用空格隔开的两个整数Sa和Sb
示例1

输入

4
1 2 3 4

输出

7 4
这是一个不符合题目要求的答案,但理论上这个答案可以完成任务(搜索路径指数爆炸),完成度为10/50。
思路是通过函数递归,直接遍历所有情况返回最大值。
import sys

lines = []

try:
    while True:  # 获取所有输入
        line = sys.stdin.readline().strip()
        if line == "":
            break
        lines.append(line.split())
except:
    pass
N = int(lines[0][0])
l = []
for i in lines[1]:
    l.append(int(i))
del lines


# 搜索路径本质是一个二叉树,那么从树枝向上传播,即可得到最优解
def search(Sa, Sb, l, A, B, term):
    # Sa,Sb为A,B当前的总分
    # l是剩余的数字
    # A,B是A,B上次取的数字
    if len(l) > 0:  # 如果l还没取完
        if term:  # 轮到A
            SaR, SbR = search(Sa + abs(l[0] - A), Sb, l[1:], l[0], B, False)
            SaL, SbL = search(Sa + abs(l[-1] - A), Sb, l[:-1], l[-1], B, False)
            if SaR < SaL:  # A的回合,A会选择对自己有利的
                return SaL, SbL
            else:
                return SaR, SbR
        else:  # 轮到B
            SaR, SbR = search(Sa, Sb + abs(l[0] - B), l[1:], A, l[0], True)
            SaL, SbL = search(Sa, Sb + abs(l[-1] - B), l[:-1], A, l[-1], True)
            if SbR < SbL:  # B的回合,B会选择对自己有利的
                return SaL, SbL
            else:
                return SaR, SbR
    # l被取完后,统计总分
    return Sa, Sb


SaM, SbM = search(0, 0, l, 0, 0, True)
print(SaM, SbM)


发表于 2023-04-21 00:01:19 回复(0)