当前位置:首页 » 《休闲阅读》 » 正文

【C++动态规划 BFS 博弈】3283. 吃掉所有兵需要的最多移动次数|2473

18 人参与  2024年12月08日 18:02  分类 : 《休闲阅读》  评论

点击全文阅读


本文涉及知识点

C++动态规划
C++BFS算法
数学 博弈

LeetCode3283. 吃掉所有兵需要的最多移动次数

给你一个 50 x 50 的国际象棋棋盘,棋盘上有 一个 马和一些兵。给你两个整数 kx 和 ky ,其中 (kx, ky) 表示马所在的位置,同时还有一个二维数组 positions ,其中 positions[i] = [xi, yi] 表示第 i 个兵在棋盘上的位置。
Alice 和 Bob 玩一个回合制游戏,Alice 先手。玩家的一次操作中,可以执行以下操作:
玩家选择一个仍然在棋盘上的兵,然后移动马,通过 最少 的 步数 吃掉这个兵。注意 ,玩家可以选择 任意 一个兵,不一定 要选择从马的位置出发 最少 移动步数的兵。
在马吃兵的过程中,马 可能 会经过一些其他兵的位置,但这些兵 不会 被吃掉。只有 选中的兵在这个回合中被吃掉。
Alice 的目标是 最大化 两名玩家的 总 移动次数,直到棋盘上不再存在兵,而 Bob 的目标是 最小化 总移动次数。
假设两名玩家都采用 最优 策略,请你返回可以达到的 最大 总移动次数。

在一次 移动 中,如下图所示,马有 8 个可以移动到的位置,每个移动位置都是沿着坐标轴的一个方向前进 2 格,然后沿着垂直的方向前进 1 格。

在这里插入图片描述

示例 1:

输入:kx = 1, ky = 1, positions = [[0,0]]

输出:4

解释:
在这里插入图片描述

马需要移动 4 步吃掉 (0, 0) 处的兵。

示例 2:

输入:kx = 0, ky = 2, positions = [[1,1],[2,2],[3,3]]

输出:8
在这里插入图片描述

解释:
Alice 选择 (2, 2) 处的兵,移动马吃掉它需要 2 步:(0, 2) -> (1, 4) -> (2, 2) 。
Bob 选择 (3, 3) 处的兵,移动马吃掉它需要 2 步:(2, 2) -> (4, 1) -> (3, 3) 。
Alice 选择 (1, 1) 处的兵,移动马吃掉它需要 4 步:(3, 3) -> (4, 1) -> (2, 2) -> (0, 3) -> (1, 1) 。
示例 3:
输入:kx = 0, ky = 0, positions = [[1,2],[2,4]]
输出:3
解释:
Alice 选择 (2, 4) 处的兵,移动马吃掉它需要 2 步:(0, 0) -> (1, 2) -> (2, 4) 。注意,(1, 2) 处的兵不会被吃掉。
Bob 选择 (1, 2) 处的兵,移动马吃掉它需要 1 步:(2, 4) -> (1, 2) 。
提示:
0 <= kx, ky <= 49
1 <= positions.length <= 15
positions[i].length == 2
0 <= positions[i][0], positions[i][1] <= 49
positions[i] 两两互不相同。
输入保证对于所有 0 <= i < positions.length ,都有 positions[i] != [kx, ky] 。

BFS +动态规划之记忆化搜索 + 博弈

注意:国际象棋没有马腿。
n = pos.length
pos2 = pos, pos追加{kx,ky}
dis[i][j] 记录pos[i]到pos[j]的最少跳跃次数。

动态规划的状态表示

dp[i][m] 记录吃光剩余兵需要的跳跃次数。马在pos2[i],(1<<i)&m表示第i个兵是否存活。为了方便,增加变量bTurn表示当前回合是否是Alice的回合。
dp[i][m] 为-1表示未0处理。

记忆化搜索的函数Rec

函数的参数:i,m,bTurn
如果m等于0,return 0。
如果dp[i][m]不是-1,return dp[i][m]。
如果bTurn ,
枚举存活的兵j
return dp[i][m] = max(dis[i][j] + Rec(j,m ^( 1 << j ),false)
如果是Bom的回合:
return dp[i][m] = min(dis[i][j] + Rec(j,m ^( 1 << j ),true)

初始调用

return Rec(n,(1<<n)-1,true)

代码

核心代码

class Solution {public:int maxMoves(int kx, int ky, vector<vector<int>>& positions) {const int N = positions.size();const int N2 = N + 1;vector<pair<int, int>> pos2;for (const auto& v : positions) {pos2.emplace_back(v[0], v[1]);}pos2.emplace_back(kx,ky);vector<vector<int>> dis(N2, vector<int>(N2));for (int i = 0; i < N2; i++) {auto dis1 = Dis(pos2[i].first, pos2[i].second);for (int j = 0; j < N2; j++) {dis[i][j] = dis1[pos2[j].first][pos2[j].second];}}vector<vector<int>> dp(N2, vector<int>(1 << N,-1));function<int(int, int, bool)> Rec = [&](int pos, int mask, bool bTurn) {if (0 == mask) { return 0; }if (-1 != dp[pos][mask]) {return  dp[pos][mask];}int a[2] = { INT_MAX / 2,INT_MIN / 2 };for (int i = 0; i < N; i++) {if (!((1 << i) & mask)) { continue; }if (bTurn) {a[bTurn] = max(a[bTurn], Rec(i, mask ^ (1 << i), !bTurn) + dis[pos][i]);}else {a[bTurn] = min(a[bTurn], Rec(i, mask ^ (1 << i), !bTurn) + dis[pos][i]);}}return dp[pos][mask]= a[bTurn];};return Rec(N,( 1 << N)-1, true);}vector<vector<int>> Dis(int x, int y) {const int iNotMay = 1'000'000;vector<vector<int>> dis(50, vector<int>(50, iNotMay));queue<pair<int, int>> que;auto Add = [&](int x, int y,int iDis) {if ((x < 0) || (x >= 50)) { return; }if ((y < 0) || (y >= 50)) { return; }if (iNotMay != dis[x][y]) { return; }dis[x][y] = iDis;que.emplace(x, y);};pair<int,int> moves[] = { {1,1},{1,-1},{-1,1},{-1,-1} };Add(x, y, 0);while (que.size()) {const auto [x, y] = que.front();que.pop();for (const auto& [x1, y1] : moves){Add(x + 2*x1, y + y1, dis[x][y] + 1);Add(x+x1,y+ 2*y1, dis[x][y] + 1);}}return dis;}};

单元测试

int kx,  ky;vector<vector<int>> positions;TEST_METHOD(TestMethod11){kx = 1, ky = 1, positions = { {0,0} };auto res = Solution().maxMoves(kx, ky, positions);AssertEx(4, res);}TEST_METHOD(TestMethod12){kx = 0, ky = 2, positions = { {1,1},{2,2},{3,3} };auto res = Solution().maxMoves(kx, ky, positions);AssertEx(8, res);}TEST_METHOD(TestMethod13){kx = 0, ky = 0, positions = { {1,2},{2,4} };auto res = Solution().maxMoves(kx, ky, positions);AssertEx(3, res);}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。


点击全文阅读


本文链接:http://zhangshiyu.com/post/198256.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1