蓝桥-13届-C++-A组-省赛-B题-灭鼠先锋
题意在于对于所有可能的四种情况,是否先手必胜
完全没思路,直接看答案:
1、首先确定结束状态:只剩下 1 个棋子时为必败态
2、博弈状态转移基本策略:
- 可以转移到必败态的状态,为必胜态
- 只能转移到必胜态的状态,为必败态
怎么理解这两句话?
首先是对 必胜态/必败态的定义
必胜态:对于当前的博弈局面,当前玩家可以通过正确的策略,保证必定取得胜利
必败态:当前玩家无论如何都会失败
注意:在不考虑平局态的情况下,必胜态+必败态=所有的可能
可能胜也可能败的状态属于必胜态。
这是因为对于某个玩家来说,只要存在一种策略可以使得这个玩家赢得比赛,那么这个状态就是必胜态
// 判断是否仅存在一个空格(O) // 扫描字符串并对O的数量计数 bool check(string s) { int tot = 0; for (auto x : s) if (x == 'O') tot++; return tot == 1; } map<string, bool> sg; /* * 后手必胜/必败 */ bool dfs(string str) { if (sg.count(str)) return sg[str];// 记忆化 // 如果只有一个空位,也就是说后手必败 if (check(str)) return sg[str] = false;// 先赋值后返回,可读性差 /* * 模拟放一个的情况 */ for (int i = 0; i < str.size(); i++) { if (str[i] == 'O') { string temp = str; temp[i] = 'X'; // 可达必败均为必胜 // 意思是存在当前选手下了某一步棋之后,后面的选手不管怎么下都必败 if (!dfs(temp)) return sg[str] = true; } } /* * 模拟放两个的情况 */ for (int i = 0; i < str.size() - 1; i++) { // i!=3是什么意思?因为这里是把两行排成一行了,不能第一行最后一个+第二行第一个算作连续两个 if (str[i] == 'O' && str[i + 1] == 'O' && i != 3) { string temp = str; temp[i] = temp[i + 1] = 'X'; // 可达必败均为必胜 if (!dfs(temp)) return sg[str] = true; } } // 只达必胜均为必败 // 排除了所有可能到达必败态的情况,接下来不管自己或者下一步对方怎么下对方都必胜,自己必败 return sg[str] = false; } int main() { // 表示棋盘的四种状态 string s[] = { "XOOOOOOO", "XXOOOOOO", "OXOOOOOO", "OXXOOOOO" }; for (string str : s) { if (dfs(str))cout << 'L';// 后手必胜 else cout << 'V'; } return 0; }
代码中模拟了所有的可能放置情况,并对其做了记忆以提高效率
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/17196355.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步