蓝桥杯 填字母游戏

填字母游戏

原题目链接

问题背景

小明沉迷 LOL。K 大师与他先玩一个"在空格中填字母"的小游戏:

两人轮流在一行格子中,把某个空格替换为 LO。谁先在整行字符串中形成子串 "LOL" ,谁就获胜 ;若所有格子填满仍无法形成 "LOL",则平局

游戏规则

  • 初始给定一行由 LO*(表示空格)组成的字符串。
  • 两名玩家轮流行动,每回合:
    • 选择任意一个 *,将其替换为 LO
  • 判定:
    • 任何时刻,一旦行内出现连续的 "LOL",当前行动的玩家立刻获胜
    • 若所有 * 均被替换完仍未出现 "LOL",则平局

目标

对每个给定的初始局面,假设小明先手 且双方都采用最优策略,输出小明能达到的最好结果

  • 1:先手必胜;
  • 0:先手可保平;
  • -1:先手必败。

输入格式

  • 第 1 行:整数 nn < 10),表示有 n 个初始局面。
  • 接下来的 n 行:每行一个只包含 LO* 的字符串,表示一个初始局面(例如:
    • "******":6 个空格;
    • "L****":左端一个 L,其后 4 个空格)。

输出格式

  • 输出 n 行,每行一个整数,分别对应每个初始局面的最好结果:
    • 10-1(含义见上文"目标")。

示例

输入

in 复制代码
4
***
L**L
L**L***L
L*****L

输出

out 复制代码
0
-1
1
1

c++代码

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

int n;
string s;
unordered_map<string, int> mp;

int result() {
    if (mp.find(s) != mp.end()) return mp[s];
	if (s.find("LOL") != -1) {mp[s] = -1; return -1;}
	if (s.find("*") == -1) {mp[s] = 0; return 0;}
	int key = -1;
	for (int i = 0; i < s.size(); i++) {
		if (s[i] != '*') continue;
		s[i] = 'L';
		int sym = result();
		if (sym == -1) {
			s[i] = '*';
			mp[s] = 1;
			return 1;
		}
		else if (sym == 0) key = 0;
		s[i] = 'O';
		sym = result();
		if (sym == -1) {
			s[i] = '*';
			mp[s] = 1;
			return 1;
		}
		else if (sym == 0) key = 0;
		s[i] = '*';
	}
	mp[s] = key;
	return key;
}

int main() {
	cin >> n;
	while (n--) {
		cin >> s;
		cout << result() << endl;
	}
	return 0;
}

题目解析

博弈论(递归+回溯)

如果敌方必赢,那么我方必输,如果敌方必输那么我方必赢。否则可以平局。

c++ 复制代码
if (sym == -1) {
    return 1;
}

int sym()的返回值表示,当前局面,先下棋的人的输赢。

我们枚举先下棋的人这一步的每一种下法。

cpp 复制代码
for (int i = 0; i < s.size(); i++) {
    if (s[i] != '*') continue;
    s[i] = 'L';
    //...省略代码
    s[i] = '*';.//回溯
    //...省略代码
    s[i] = 'O';
    s[i] = '*';//回溯
}

然后下一步就轮到敌方下。我们再次调用sym函数获得敌方输赢。

cpp 复制代码
s[i] = 'L';
int sym = result();
if (sym == -1) {
    //...
    return 1;
}

一直枚举每一种下法,直到已经分出胜负才停止。

如果敌方的每一种返回值都是必赢那么我们必输。

如果敌方只要有一个必输那么我们必赢。

否则可以平局。

记忆化搜索

递归过程中会出现很多重复情况,而每一种情况的返回值都是一样的。

为了不重复走我们已经模拟过的情况,我们用unorder_map把我们走过的每一种情况存储下来。

下次我们遇到重复的情况的时候,直接返回存储的值,而不是再次递归搜索。

cpp 复制代码
if (mp.find(s) != mp.end()) return mp[s];
相关推荐
我材不敲代码13 小时前
Python实现打包贪吃蛇游戏
开发语言·python·游戏
2501_9209317013 小时前
React Native鸿蒙跨平台采用ScrollView的horizontal属性实现横向滚动实现特色游戏轮播和分类导航
javascript·react native·react.js·游戏·ecmascript·harmonyos
测试涛叔17 小时前
金三银四软件测试面试题(800道)
软件测试·面试·职场和发展
2501_9209317017 小时前
React Native鸿蒙跨平台实现推箱子游戏,完成玩家移动与箱子推动,当所有箱子都被推到目标位置时,玩家获胜
javascript·react native·react.js·游戏·ecmascript·harmonyos
Angelina_Jolie18 小时前
一文搞懂 SCI、SSCI、CSSCI、C 刊、核心期刊:定义、作用、层级对比及投稿选择
考研·职场和发展·创业创新
User_芊芊君子19 小时前
【LeetCode经典题解】搞定二叉树最近公共祖先:递归法+栈存路径法,附代码实现
算法·leetcode·职场和发展
熬夜造bug19 小时前
LeetCode Hot100 刷题路线(Python版)
算法·leetcode·职场和发展
一起养小猫19 小时前
Flutter for OpenHarmony 实战:别踩白方块游戏完整开发指南
flutter·游戏
星空露珠20 小时前
速算24点所有题库公式
开发语言·数据库·算法·游戏·lua
晚霞的不甘1 天前
Flutter for OpenHarmony从零到一:构建《冰火人》双人合作闯关游戏
android·flutter·游戏·前端框架·全文检索·交互