ACM-ICPC 2018 徐州赛区网络预赛 B. BE, GE or NE

本文介绍了一种基于回合制博弈的游戏算法实现,通过动态规划的方法,玩家A和B交替行动以达到各自的最优目标:A追求分数不低于k,而B则希望分数不超过l。通过状态转移方程和边界条件的设定,最终确定了游戏结局的状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题解

题目意思 给你n个回合轮流出牌 A先手 A想让分数大于等于k B想让分数小于等于l
在双方都足够聪明的情况下 最终结果是大于k还是小于l

按照题意初始化n+1回合 大于等于k(1)小于等于l(-1)还是l和k之间(0)
d[i][j] 表示第i回合 分数为j的情况
倒着回合 枚举每个状态 负值用100往上的下标表示
A出牌的时候让结果尽量大(取max) B让结果尽量小(取min) 最后d[1][(m的正确下标)]为答案

AC代码

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MAXN = 1e3 + 10;
const int MAXM = 2e2 + 10;
int d[MAXN][MAXM];
int a[MAXN], b[MAXN], c[MAXN];

int cal(int x)
{
    x = min(max(x, -100), 100);
    if (x < 0)
        x = -x + 100;
    return x;
}
int main()
{
#ifdef LOCAL
    freopen("C:/input.txt", "r", stdin);
#endif
    memset(d, 0x3f, sizeof(d));
    int n, m, k, l;
    cin >> n >> m >> k >> l;
    for (int i = 1; i <= n; i++)
        scanf("%d%d%d", &a[i], &b[i], &c[i]);
    for (int i = 0; i <= 200; i++) //n+1回合为结束
    {
        int v = i; //真正值
        if (v > 100)
            v = -(v - 100);
        if (v >= k)
            d[n + 1][i] = 1;
        else if (v <= l)
            d[n + 1][i] = -1;
        else
            d[n + 1][i] = 0;
    }
    for (int i = n; i >= 1; i--) //第几轮
    {
        for (int j = 0; j <= 200; j++) //值下标
        {
            int v = j, fst = 1; //真正值
            if (v > 100)
                v = -(v - 100);
            if (i & 1) //好
            {
                if (a[i] && d[i + 1][cal(v + a[i])] != INF)
                {
                    if (fst)
                        d[i][j] = d[i + 1][cal(v + a[i])];
                    else
                        d[i][j] = max(d[i][j], d[i + 1][cal(v + a[i])]);
                    fst = 0;
                }
                if (b[i] && d[i + 1][cal(v - b[i])] != INF)
                {
                    if (fst)
                        d[i][j] = d[i + 1][cal(v - b[i])];
                    else
                        d[i][j] = max(d[i][j], d[i + 1][cal(v - b[i])]);
                    fst = 0;
                }
                if (c[i] && d[i + 1][cal(-v)] != INF)
                {
                    if (fst)
                        d[i][j] = d[i + 1][cal(-v)];
                    else
                        d[i][j] = max(d[i][j], d[i + 1][cal(-v)]);
                }
            }
            else //坏
            {
                if (a[i] && d[i + 1][cal(v + a[i])] != INF)
                {
                    if (fst)
                        d[i][j] = d[i + 1][cal(v + a[i])];
                    else
                        d[i][j] = min(d[i][j], d[i + 1][cal(v + a[i])]);
                    fst = 0;
                }
                if (b[i] && d[i + 1][cal(v - b[i])] != INF)
                {
                    if (fst)
                        d[i][j] = d[i + 1][cal(v - b[i])];
                    else
                        d[i][j] = min(d[i][j], d[i + 1][cal(v - b[i])]);
                    fst = 0;
                }
                if (c[i] && d[i + 1][cal(-v)] != INF)
                {
                    if (fst)
                        d[i][j] = d[i + 1][cal(-v)];
                    else
                        d[i][j] = min(d[i][j], d[i + 1][cal(-v)]);
                }
            }
        }
    }
    if (m < 0)
        m = -m + 100;
    if (d[1][m] == 1)
        cout << "Good Ending" << endl;
    else if (d[1][m] == -1)
        cout << "Bad Ending" << endl;
    else
        cout << "Normal Ending" << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值