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

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

时间:2024-12-05 17:58:17浏览次数:11  
标签:return int positions C++ BFS ky kx 3283 dis

本文涉及知识点

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++**实现。

标签:return,int,positions,C++,BFS,ky,kx,3283,dis
From: https://blog.csdn.net/he_zhidan/article/details/144092100

相关文章

  • C++(fprintf())
    目录1.函数定义2.常见格式说明符3.示例代码4.适用场景fprintf()是C和C++中用于格式化输出到文件的标准库函数。它的功能类似于printf(),但与printf()不同的是,fprintf()将格式化后的数据输出到指定的文件,而不是标准输出流(通常是屏幕)。1.函数定义intfprintf(FILE......
  • (2024最新毕设合集)基于SSM的河北省博物馆管理系统-02350|可做计算机毕业设计JAVA、PHP
    目 录摘要1绪论1.1选题背景与意义1.2国内外研究现状1.3论文结构与章节安排2 河北省博物馆管理系统系统分析2.1可行性分析2.1.1技术可行性分析2.1.2 经济可行性分析2.1.3操作可行性分析2.2系统功能分析2.2.1功能性分析2.2.2非功能性分析......
  • 【C++】7000字剖析红黑树的概念规则和底层代码实现
    目录一、红黑树的概念二、怎么做到最长路径与最短路径相差小于等于两倍?(性质)     三、极端场景分析最长路径和最短路径:四、AVL树和红黑树的效率对比:五、树的路径包括叶子结点的空结点六、红黑树的插入结点时的相关规则:(一)、插入结点的颜色必须为红色(二)、处理规......
  • 冷门知识点:C++如何调试
    哈喽大家好,我是@学霸小羊,今天讲一个比较冷门的东西:C++如何调试。前几天我想要调试一个代码,搞半天,还没调出来。我在网上搜了半天,都是要下载一些诸如gdb之类的软件,我实在是不想下载这些五花八门的软件了,于是和我的损友研究了半天,总算研究出来了。注:以Dev-C++ 5.10版本进行讲......
  • 【C++】类的继承的深入探讨
    继承是扩展现有类并为基类提供新功能的一种方式。本文主要探讨一个问题:子类会包含父类所包含的一切吗?起初,作者认为这个问题的答案是否定的,因为子类无法访问父类的private成员但是,运行下述一个简易的示例代码,得到Entity类和Player类的大小分别是8和16。#include<iostream>cla......
  • 反转字符串中每个单词的字符顺序,但保持单词之间的相对顺序不变(C++)
     需求:用户输入一行字符(一个英语句子lastweek,Iwenttocinima.),将该行字符按照每个单词逆序输出(即输出:tsalkeew,Itnewotaminic.)。要求1.写一个函数用来实现每个单词的字符顺序颠倒,拿到头和尾,对代码进行遍历(判断是否为单词首字母:当前为字母,前面是空格或者什么都没有;判......
  • 【最新原创毕设】基于SpringBoot的网上报修平台+94800(免费领源码)可做计算机毕业设计JA
    摘要随着信息技术的快速发展和普及,高校宿舍管理面临着诸多挑战与机遇。传统的宿舍管理模式,如手工记录报修信息、纸质文档管理等,已无法满足现代高校对效率和便捷性的需求。因此,开发一套高效、智能的网上报修平台显得尤为重要。基于springBoot的网上报修平台的设计和实现正......
  • c++实验五
    task1:publisher.hpp:1#pragmaonce23#include<iostream>4#include<string>56usingstd::cout;7usingstd::endl;8usingstd::string;910//发行/出版物类:Publisher(抽象类)11classPublisher{12public:13Publisher(const......
  • 使用 C++ 调用 YOLOv3 模型进行物体检测
    环境准备首先,确保你已经安装了以下工具:OpenCV:用于图像处理。Darknet:用于YOLO模型的推理。C++编译器:如g++。2.安装Darknet克隆Darknet仓库并进入目录:bashgitclonehttps://github.com/pjreddie/darknet.gitcddarknet使用Makefile编译Darknet(如果使用GPU......
  • [C++]常用的windows控制台操作
    目录一、光标1.隐藏光标2.移动光标二、窗口大小1.调整大小2、固定大小三、颜色1.cmd命令2.直接printf颜色四、控制台1.标题一些常用的控制台操作!注意:该文章全程需要:Windows.h头文件,因为使用了Windows的API一、光标1.隐藏光标voidHideCursor(){ CONSOLE_CURSOR_I......