P9586 「MXOI Round 2」游戏

记录71

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	int t,c1,c2,c3,d1,d2,d3;
	cin>>t;
	while(t--){
		int x=0;
		cin>>c1>>c2>>c3>>d1>>d2>>d3;
		if(c1>d2||c3>d1) x=1;
		if(x==1){
			cout<<"C"<<endl;
			continue;
		} 
		d1-=c3;
		if(d1>c2||d3>c1) x=2;
		if(x==2){
			cout<<"D"<<endl;
			continue;
		}
		if(x==0) cout<<"E"<<endl;
	}
	return 0;
}

题目传送门https://www.luogu.com.cn/problem/P9586


突破口

  • 杀:对对方使用,对方需要使用一张 ,否则对方输掉游戏; 回应对方的

  • 闪:回应对方的

  • 斩:对对方使用,对方需要使用一张,否则对方输掉游戏。

从小 C 开始

小 C 共有 c1​ 张杀、c2​ 张闪、c3​ 张斩,小 D 共有 d1​ 张杀、d2​ 张闪、d3​ 张斩,双方都知道对方的手牌。你需要求出,双方在都进行最优策略的情况下,游戏的结果会如何。


思路

  1. 小 C 先手,能否直接获胜 👉 杀赢 或 斩赢

  2. 如果小 C 不能先手赢,轮到小 D 反击 👉 杀赢 或 斩赢

  3. 平局


代码简析

  • 读入测试数据组数 t
  • c1, c2, c3:小 C 的 杀、闪、斩 数量。
  • d1, d2, d3:小 D 的 杀、闪、斩 数量。
cpp 复制代码
    while(t--){
        int x = 0;
        cin >> c1 >> c2 >> c3 >> d1 >> d2 >> d3;
  • 对每组数据,初始化结果标志 x = 0(0 表示尚未分出胜负,可能平局)。

🔥 第一步:小 C 先手,能否直接获胜?

cpp 复制代码
        if(c1 > d2 || c3 > d1) x = 1;
💡 分析:

小 C 在第一回合可以出:

  • 最多 c1 → 小 D 需要至少 c1闪(d2) 来全部抵消
  • 最多 c3 → 小 D 需要至少 c3杀(d1) 来全部抵消

如果 c1 > d2 :小 D 的闪不够挡所有"杀" → 小 C 出 d2+1 张杀,小 D 无法全挡 → 小 C 赢

如果 c3 > d1 :小 D 的杀不够挡所有"斩" → 小 C 出 d1+1 张斩,小 D 无法全挡 → 小 C 赢

✅ 所以只要满足任一条件,小 C 先手必胜

cpp 复制代码
        if(x == 1){
            cout << "C" << endl;
            continue;
        }
  • 如果 x == 1,输出 "C",跳过后续逻辑。

🔥 第二步:如果小 C 不能先手赢,轮到小 D 反击

cpp 复制代码
        d1 -= c3;
💡 为什么减 c3
  • 小 C 虽然不能直接赢,但会最优出牌
  • 由于 c3 <= d1(否则上一步已赢),小 C 一定会出 全部 c3 张斩(因为不出浪费,且对己无害)。
  • 小 D 必须用 c3 张杀 来抵消这些斩 → 所以小 D 剩下的杀为:d1 - c3

✅ 这是双方最优策略下的必然消耗。

cpp 复制代码
        if(d1 > c2 || d3 > c1) x = 2;
💡 现在轮到小 D 的回合(第二回合),他能否反杀?

小 D 此时可以出:

  • :最多 d1(已减去用于挡斩的部分)
  • :最多 d3

小 C 需要:

  • 闪(c2) 挡小 D 的杀
  • 杀(c1) 挡小 D 的斩

所以:

  • 如果 d1 > c2:小 D 出 c2+1 张杀,小 C 闪不够 → 小 D 赢
  • 如果 d3 > c1:小 D 出 c1+1 张斩,小 C 杀不够 → 小 D 赢

✅ 满足任一,小 D 在第二回合必胜。

cpp 复制代码
        if(x == 2){
            cout << "D" << endl;
            continue;
        }
  • 输出 "D",结束本组。

🤝 第三步:双方都无法在前两回合取胜 → 平局

cpp 复制代码
        if(x == 0) cout << "E" << endl;
💡 为什么是平局?
  • 小 C 先手无法赢(c1 ≤ d2c3 ≤ d1
  • 小 D 反击也无法赢(d1 - c3 ≤ c2d3 ≤ c1

此时:

  • 小 C 出完所有斩(c3),小 D 用 c3 张杀挡掉
  • 小 D 出完所有斩(d3),小 C 用 d3 张杀挡掉
  • 剩余的杀/闪也足够互相抵消

➡️ 双方进入"互相有解"的状态,谁也不敢贸然出牌(因为出多少都能被挡),于是都不出牌,游戏无限进行 → 平局

题目中"平局"定义为"谁也无法获胜",符合此情况。


✅ 总结:博弈逻辑链

阶段 条件 结果
小 C 先手 c1 > d2c3 > d1 C 赢
小 D 反击 (d1 - c3) > c2d3 > c1 D 赢
否则 所有攻击都能被防御 平局(E)

补充

在 CSP(尤其是 CSP-J/S 初赛和复赛) 中,像"小 C 和小 D 打牌"这类博弈模拟 + 最优策略判断的题目非常典型。它们看似复杂,但其实有清晰的解题套路和技巧。

下面为你系统总结这类题在 CSP 中的 核心思想、常见模型与应试技巧:

✅ 一、题型识别:这是什么题?

这类题通常具有以下特征:

两人轮流操作(A 先手,B 后手)

双方信息完全公开(知道对方所有状态)

每一步操作有明确规则和代价

目标是判断:先手胜 / 后手胜 / 平局

强调"最优策略"(即双方都尽可能让自己赢、阻止对方赢)

📌 这类题不是搜索或 DP,而是 逻辑推理 + 贪心模拟!

✅ 二、核心解题思路(CSP 高频套路)

🔑 技巧 1:分阶段分析回合

CSP 的博弈题通常只涉及 前 1~2 个回合 就能决定胜负,因为:

如果先手能在第一回合直接获胜 → 先手必胜

如果不能,后手是否能在第二回合反杀?

如果都不能 → 双方进入"互相有解"状态 → 平局

💡 CSP 不考复杂博弈论(如 SG 函数),只考 有限步内的必胜/必败判断!

🔑 技巧 2:"最大压力测试"思维

先手会 尽可能出最多的攻击牌(比如全部"杀"+"斩")

判断对方 防御资源是否足够

杀 ←→ 闪

斩 ←→ 杀

如果防不住 → 赢;如果防得住 → 进入下一阶段

🔑 技巧 3:资源消耗要更新

第一回合结束后,防御方的资源会被消耗

例如:C 出了 c3 张斩 → D 必须用 c3 张杀来挡 → D 剩余杀 = d1 - c3

第二回合要用剩余资源判断是否能反杀

🔑 技巧 4:平局 = 双方都无法突破

当且仅当:

先手攻不破后手防御

后手也攻不破先手防御

此时理性玩家会选择 不出牌(避免浪费),游戏无限循环 → 平局

✅ 三、CSP 常见博弈模型(背下来!)

表格

模型 特点 解法

卡牌对攻型(本题) 杀/闪/斩互克 分两回合模拟资源消耗

取石子类 每次取 1~k 个,最后取光者胜 判断 n % (k+1)(巴什博弈)

分糖果/分物品 两人轮流选,最大化自己 贪心 or 简单 DP

位置移动型 在数轴上移动,谁先到终点赢 判断距离奇偶性 or 步数

⚠️ 注意:CSP-J/S 几乎不考 Nim 博弈、SG 函数等高级内容,重点是 逻辑清晰 + 模拟准确!

✅ 四、代码实现技巧(CSP 编程题)

用标志变量记录胜负状态(如 x=0/1/2)

顺序判断:

cpp

编辑

if (先手能赢) → 输出 C

else if (后手能赢) → 输出 D

else → 输出 E

注意资源更新顺序(先消耗,再判断)

不要写递归/搜索!CSP 数据小但逻辑要快,直接 if-else 模拟

✅ 五、避坑指南(CSP 高频错误)

表格

错误 正确做法

忘记先手必须先出牌 先判断 C 能否第一回合赢

没更新 D 的剩余杀(d1 -= c3) 必须扣除用于挡斩的杀

认为"可以留牌"就有优势 最优策略下,能出就出(不留无用牌)

混淆"杀"和"斩"的应对关系 杀 ← 闪,斩 ← 杀(死记!)

✅ 六、一句话口诀(考前背诵)

"先手猛攻看防住,后手反杀算余力;

攻防皆稳无人输,平局就是 E 结局。"

✅ 总结

在 CSP 中遇到此类博弈题,记住:

不是搜索,是逻辑推理

只看前 1~2 回合

模拟资源消耗 + 最大压力测试

三结果:C / D / E,按顺序判断

掌握这套方法,这类题就是送分题!🎯

祝你在 CSP 中轻松拿下这类题目!

相关推荐
浅念-6 小时前
C语言编译与链接全流程:从源码到可执行程序的幕后之旅
c语言·开发语言·数据结构·经验分享·笔记·学习·算法
kyle~6 小时前
ROS2---QoS策略
c++·机器人·ros2
爱吃生蚝的于勒6 小时前
【Linux】进程信号之捕捉(三)
linux·运维·服务器·c语言·数据结构·c++·学习
有时间要学习6 小时前
面试150——第五周
算法·深度优先
君生我老7 小时前
C++自写list类
c++
阿猿收手吧!7 小时前
【C++】异步编程:std::async终极指南
开发语言·c++
数智工坊7 小时前
【数据结构-树与二叉树】4.6 树与森林的存储-转化-遍历
数据结构
REDcker7 小时前
gRPC开发者快速入门
服务器·c++·后端·grpc
晚霞的不甘7 小时前
Flutter for OpenHarmony 可视化教学:A* 寻路算法的交互式演示
人工智能·算法·flutter·架构·开源·音视频