news 2026/4/23 17:41:51

问题解决策略搜索训练1

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
问题解决策略搜索训练1

问题 A: 皇后问题(递归)

题目描述

编写一个函数,求解皇后问题:在 n×nn \times nn×n 的方格棋盘上,放置 nnn 个皇后,要求每个皇后不同行、不同列、不同左右对角线。

要求:

1、皇后的个数由用户输入,其值不超过 202020,输出所有的解。

2、采用递归回溯的方法解决。

输入

输入一个整数 nnn,代表棋盘的大小,

输出

将计算出的彼此不受攻击的 nnn 个皇后的所有放置方案输出,每种方案占一行。

输入输出样例

样例输入 #1

复制

4
样例输出 #1

复制

2 4 1 3 3 1 4 2

提示

1、规定搜索时每行从左向右,每列从上往下搜索!

2、尽量采用较优算法!

3、使用递归求解!

#include<iostream> #include<vector> using namespace std; int n; const int N = 1e5; vector<bool>col(N, false);//列 vector<bool>dg1(N, false);//主对角线 vector<bool>dg2(N, false);//副对角线 vector<vector<int>>ans;//答案 vector<int>tmp;//临时数组,存放每次的答案 void print(vector<vector<int>>a) { for (auto arr : a) { for (int e : arr) cout << e << " "; cout << "\n"; } } //遍历每一行 void dfs(int u) { if (u == n)//遍历完n行,就存储当前的答案 { ans.push_back(tmp); return; } for (int i = 0;i < n;i++) { if (col[i] == false && dg1[u - i + n] == false && dg2[u + i] == false) { //标记访问 col[i] = true;//行 //主对角线方向:x-y为定值,但可能为负数,故加上n dg1[u - i + n] = true; //副对角线方向:x+y为定值 dg2[u + i] = true; tmp.push_back(i + 1); dfs(u + 1); //回溯 col[i] = false; dg1[u - i + n] = false; dg2[u + i] = false; tmp.pop_back(); } } } int main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); cin >> n; dfs(0);//从第一行开始搜索 print(ans); return 0; }

问题 B: 八皇后问题

题目描述

会下国际象棋的人都很清楚: 皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8 个皇后放在棋盘(有8×88 \times88×8 个方格) 上, 使它们谁也不能被吃掉,这 就是著名的八皇后问题。 .

对于某个满足要求的八个皇后的摆放方法 ,定 义一个皇后串 a 与之对应, 即a=b1b2…b8a = b1 b2 … b8a=b1b2…b8 , 其中 bi 为相应摆法中第 i 行皇后所处的列数。已经知道八皇后问题一共有92 组解(即 92 个不同的皇后串)。

给出一个数b , 要求输出第b 个串。串的比较是这样的: 皇后串 x 置于皇后串 y 之前, 当且仅当将 x 视为整数时比 y 小。

输入


第 1 行是测试数据的组数n , 后面跟着n 行输入。每组测试数据占 1 行, 包含一个正整数b(1≤b≤92)(1 \leq b \leq 92)(1≤b≤92)

输出

输出有 n 行, 每行输出对应一个输入。输出应是一个正整数, 是对应于b 的皇后串。

输入输出样例

样例输入 #1

复制

2 1 92
样例输出 #1

复制

15863724 84136275
#include<iostream> #include<vector> using namespace std; int n; const int N = 1e5; vector<bool>col(N, false);//列 vector<bool>dg1(N, false);//主对角线 vector<bool>dg2(N, false);//副对角线 vector<vector<int>>ans;//答案 vector<int>tmp;//临时数组,存放每次的答案 //遍历每一行 void dfs(int u) { if (u == n)//遍历完n行,就存储当前的答案 { ans.push_back(tmp); return; } for (int i = 0;i < n;i++) { if (col[i] == false && dg1[u - i + n] == false && dg2[u + i] == false) { //标记访问 col[i] = true;//行 //主对角线方向:x-y为定值,但可能为负数,故加上n dg1[u - i + n] = true; //副对角线方向:x+y为定值 dg2[u + i] = true; tmp.push_back(i + 1); dfs(u + 1); //回溯 col[i] = false; dg1[u - i + n] = false; dg2[u + i] = false; tmp.pop_back(); } } } int main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); n = 8; dfs(0);//从第一行开始搜索 int t; cin >> t; while (t--) { int x; cin >> x; if (x >= 1 && x <= 92) { for (int e : ans[x - 1]) cout << e; cout << "\n"; } } return 0; }

问题 E: 搜索基础之红与黑

题目描述

有一间长方形的房子,地上铺了白色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。

输入

包括多个数据集合。每个数据集合的第一行是两个整数 WWW 和 HHH,分别表示 xxx 方向和 yyy 方向瓷砖的数量。WWW 和 HHH都不超过 20。在接下来的 HHH 行中,每行包括 WWW 个字符。每个字符表示一块瓷砖的颜色,规则如下
1).:黑色的瓷砖;
2)#:白色的瓷砖;
3)@:黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。
当在一行中读入的是两个零时,表示输入结束。

输出

对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。

输入输出样例

样例输入 #1

复制

6 9 ....#. .....# ...... ...... ...... ...... ...... #@...# .#..#. 0 0
样例输出 #1

复制

45
#include<iostream> #include<vector> #define int long long using namespace std; int dx[4] = { 0,0,1,-1 }; int dy[4] = { 1,-1,0,0 }; int cnt = 0; int n = 1, m = 1; //要加引用&,不然函数里面的改变不影响外层 void dfs(int x, int y, vector<vector<bool>>&vis, vector<vector<char>>&g) { //先卡边界 if (x < 0 || x >= n || y < 0 || y >= m) return; if (vis[x][y] == true) return; if (g[x][y] == '#') return; vis[x][y] = true; cnt++;//计数 for (int i = 0;i < 4;i++) { int cx = x + dx[i]; int cy = y + dy[i]; if (cx < 0 || cx >= n || cy < 0 || cy >= m) continue; dfs(cx, cy, vis, g); } } signed main() { int sx = 0; int sy = 0; while (cin >> m >> n && n != 0 && m != 0) { vector<vector<bool>>vis(n, vector<bool>(m, false)); vector<vector<char>>g(n, vector<char>(m)); for (int i = 0;i < n;i++) { for (int j = 0;j < m;j++) { cin >> g[i][j]; if (g[i][j] == '@') { sx = i; sy = j; } } } dfs(sx, sy, vis, g); cout << cnt << endl; cnt = 0; } return 0; }

问题 F: 搜索基础之棋盘问题

题目描述

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 kkk 个棋子的所有可行的摆放方案 CCC。

输入

输入含有多组测试数据。

每组数据的第一行是两个正整数 nnn kkk,用一个空格隔开,表示了将在一个 n×nn \times nn×n 的矩阵内描述棋盘,以及摆放棋子的数目。0<n≤80 \lt n \le 80<n≤8 0<k≤n0 \lt k \le n0<k≤n
当为-1 -1时表示输入结束。

随后的 nnn 行描述了棋盘的形状:每行有 nnn 个字符,其中#表示棋盘区域,.表示空白区域(数据保证不出现多余的空白行或者空白列)。

输出

对于每一组数据,给出一行输出,输出摆放的方案数目 CCC (数据保证 C<231C \lt 2^{31}C<231)。

输入输出样例

样例输入 #1

复制

2 1 #. .# 4 4 ...# ..#. .#.. #... -1 -1
样例输出 #1

复制

2 1
#include<iostream> #include<vector> using namespace std; int n, k; const int N = 1e5; vector<bool>col(N, false); void dfs(int u, vector<vector<char>>g, int& cnt) { if (u == k) { cnt++; return; } for (int i = 0;i < n;i++) { if (col[i] == false && g[u][i] == '#') { col[i] = true; dfs(i + 1, g, cnt); col[i] = false; } } } int main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); while (cin >> n >> k && n != -1) { int cnt = 0; vector<vector<char>>g(n, vector<char>(n)); for (int i = 0;i < n;i++) { for (int j = 0;j < n;j++) cin >> g[i][j]; } dfs(0, g, cnt); cout << cnt << "\n"; } return 0; }

问题 G: 小游戏

题目描述

你决定编写一个小游戏。游戏在一个分割成w× hw \times hw× h 个正方格子的矩形板上 进行。如图4- 2 所示,每个正 方格子上可以有一张游戏卡片, 当然也可以没有。当下面的情况满足时,认为两个游戏卡片之间有一条路径相连:路径只包含水平或者竖直的 直线段。路径不能穿过别的游戏卡片,但是允许路径临时离开矩形板。下面是一个例子。



这里在(1,3)( 1 ,3 )(1,3) 和(4,4)( 4,4 )(4,4)处的游戏卡片是可以相连的, 而在(2,3)( 2 ,3 )(2,3) 和(3,4)( 3 , 4 )(3,4) 处的游戏卡片是不相连的, 因为连接它们的每条路径都必须穿过别的游戏卡片。现在要在小游戏中判断是否存在一条满足题意的路径能连接给定的两个游戏卡片。

输入

输入包含多组数据。一个矩形板对应一组数据。每组数据的第一行包含两个整数 ww w和h(1 ≤w,h≤75)h (1 \leq w, h \leq 75)h(1 ≤w,h≤75) , 分别表示矩形板的宽度和长度。下面的 hhh 行, 每行包括 www 个字符, 表示矩形板上的游戏卡片分布情况 。使用 X 表示某个地方有一个游戏卡片, 使用空格表示某个地方没有游戏卡片。

之后的若干行中每行包含 4 个整数x1,y1,x2,(1≤x1,x2≤w,1≤y1,y2≤h)x1 , y1 ,x2, (1 \leq x1,x2 \leq w,1 \leq y1 , y2 \leq h )x1,y1,x2,(1≤x1,x2≤w,1≤y1,y2≤h)。给出两个卡片在矩形板上的位置( 注意: 矩形板左上角的坐标是(1,1)(1 ,1 )(1,1) )。输入保证这两个游戏卡片所处的位置是不相同的。如果一行上有 4 个 0 , 表示这组测试数据的结束。如果一行上给出w=h=0w = h = 0w=h=0 , 那么表示所有的输入结束 。


输出


对每一个矩形板, 输出一行 “ Board #n:Board\ \#n:Board #n:",这里 n 是输入数据的编号。然后对每一组需要测试的游戏卡片输出一行, 这一行的开头是 “ Pair m: " , 这里 m 是测试卡片的编号( 对于每个矩形板, 编号都从1 开始)。接下来, 如果可以相连, 找到连接这两个卡片的所有路径中包 含线段数最少的路径, 输出 “ k segments . " , 这里 k 是找到的最优路径中包含的线段的数目; 如果不能相连, 则输出 “ impossible. "。
每组数据之后输出一个空行。

输入输出样例

样例输入 #1

复制

5 4 XXXXX X X XXX X XXX 2 3 5 3 1 3 4 4 2 3 3 4 0 0 0 0 0 0
样例输出 #1

复制

Board #1: Pair 1: 4 segments. Pair 2: 3 segments. Pair 3: impossible.

提示

如果出现输出超限的原因参考以下地图读入代码:

for(int i=1; i<=h; i++) { for(int j=1; j<=w; j++) { char ch = getchar(); while(ch != ' ' && ch != 'X') { ch = getchar(); } if(ch=='X') mp[i][j]=1; } }

如果出现时间超限的问题请考虑切换搜索方向。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 17:41:44

3分钟快速上手QtScrcpy:跨平台Android投屏控制的完整指南

3分钟快速上手QtScrcpy&#xff1a;跨平台Android投屏控制的完整指南 【免费下载链接】QtScrcpy Android real-time display control software 项目地址: https://gitcode.com/GitHub_Trending/qt/QtScrcpy QtScrcpy是一款强大的开源Android屏幕镜像与控制软件&#xff…

作者头像 李华
网站建设 2026/4/23 17:41:34

告别手动敲代码:用VCS的ralgen命令5分钟搞定UVM寄存器模型生成

5分钟自动化生成UVM寄存器模型&#xff1a;VCS ralgen高效实战指南 芯片验证工程师每天最头疼的事情之一&#xff0c;莫过于寄存器规格变更后需要手动更新UVM模型。我曾经在一个项目中&#xff0c;因为寄存器地址偏移量调整&#xff0c;不得不通宵修改了200多个寄存器定义——这…

作者头像 李华
网站建设 2026/4/23 17:40:48

Matlab R2023b绘图进阶:手把手教你用legend定制专属图例位置和样式

Matlab R2023b绘图进阶&#xff1a;手把手教你用legend定制专属图例位置和样式 在数据可视化领域&#xff0c;图例不仅是信息的标注工具&#xff0c;更是图表专业度的视觉名片。Matlab R2023b对图形系统进行了多项底层优化&#xff0c;其中图例&#xff08;legend&#xff09;的…

作者头像 李华
网站建设 2026/4/23 17:40:30

任务管理软件哪个好用?2026 年 12 款产品横评盘点

本文将深入对比 12 款主流任务管理工具&#xff1a;Worktile、PingCode、Jira、Asana、monday.com、ClickUp、Trello、Notion、Smartsheet、Wrike、Basecamp、Microsoft Planner。很多企业在找任务管理工具时&#xff0c;表面上是在比较功能&#xff0c;实际是在找一套能真正跑…

作者头像 李华
网站建设 2026/4/23 17:33:17

如何快速提取Godot游戏资源:专业解包工具使用指南

如何快速提取Godot游戏资源&#xff1a;专业解包工具使用指南 【免费下载链接】godot-unpacker godot .pck unpacker 项目地址: https://gitcode.com/gh_mirrors/go/godot-unpacker 想要获取Godot引擎开发的游戏中的精美素材吗&#xff1f;godot-unpacker是一款专业的Go…

作者头像 李华