搜索与回溯典型题目解析
前排提示,本文收录的题目不是全部,只是抽取一些题目进行解析。因为笔者是在写完所有题之后在写此篇,推导过程中的量的名称可能与参考代码中不一样,还望谅解。
题目链接:信息学奥赛一本通(C++版)在线评测系统
1212:LETTERS
【题目描述】
给出一个roe×col的大写字母矩阵,一开始的位置为左上角,你可以向上下左右四个方向移动,并且不能移向曾经经过的字母。问最多可以经过几个字母。
【输入】
第一行,输入字母矩阵行数R和列数S,1≤R,S≤20。
接着输出R行S列字母矩阵。
【输出】
最多能走过的不同字母的个数。
【输入样例】
3 6
HFDFFB
AJHGDH
DGAGEH
【输出样例】
6
【推导过程】
每次从一个点出发,可以向右与向下走,不能走回头路,使用vis_le[]记录已经走过的路;同时也不能走已经走过的字母,采用一个桶数组vit_[]标记走过的数组;为了记录偏移量,定义dr[]{-1,0,1,0}与dc[]{0,-1,0,1}(绕一圈的量)记录偏移量,使用循环。之后再采用搜索与回溯算法,查找可以走的路并储存。
【参考代码】
# include<iostream>
# include<cstring>
using namespace std;
const int maxn=26;
int r,s;
int g[maxn][maxn];
string ss;
int Max;
bool vis_le[maxn]; //标记字母
bool vis_[maxn][maxn];//标记点
int dr[]={1,0,-1,0};
int dc[]={0,-1,0,1};
void search(int x,int y,int step)
{
if(step>Max)
Max=step;
for(int i=0;i<4;i++)
{
int newx=x+dr[i];
int newy=y+dc[i];
if(newx>=0&&newx<r&&newy>=0&&newy<s&&!vis_le[g[newx][newy]]&&!vis_[newx][newy])
{
vis_le[g[newx][newy]]=vis_[newx][newy]=1;
search(newx,newy,step+1);
vis_le[g[newx][newy]]=vis_[newx][newy]=0;
}
}
}
int main()
{
cin>>r>>s;
for(int i=0;i<r;i++)
{
cin>>ss;
for(int j=0;j<ss.size();j++)
{
g[i][j]=ss[j]-'A';
}
}
memset(vis_le,0,sizeof(vis_le));
memset(vis_,0,sizeof(vis_));
vis_le[g[0][0]]=1;vis_[0][0]=1; //站在第一个点去向四周做选择,并把第一个点死锁
search(0,0,1); //因为第一个点有一个字母,故已访问一个字母,所以第三个参数为1
cout<<Max<<endl;
return 0;
}
1213:八皇后问题
【题目描述】
在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方。
【输入】
(无)
【输出】
按给定顺序和格式输出所有八皇后问题的解(见样例)。
【输入样例】
(无)
【输出样例】
No. 1
1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
No. 2
1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 1 0 0 0 0 0
...以下省略
【推导过程】
这是一道很经典的题目。算法的基本思路是依次在每一列的每一个点(列数不与上一个重合),并查看是否符合要求,不符合递归摆放下一个(行数加1,到达边界后行数重置,列数加1),符合记录坐标,定义a[],表示第i行的皇后在第j列。录8个摆放完毕后输出答案。皇后可以吃同一行——摆放是行数加1、同一列——建立b[],=1表示第j列有皇后了,=0就便是没有、同一对角线的棋子——先建立ysx[],表示从左下到右下的对角线,总共15条斜线,每条斜线上所有格子 行号+列号=固定值,值范围2至16;再建立yxx[],表示从左上到右下的对角线,总共15条斜线,每条斜线上所有格子 行号-列号=固定值 ,值范围7至-7(C++不能操控负数组,所以[14]并+7)。
【参考代码】
#include<iostream>
using namespace std;
int a[9];//a[i]=j 记录第i行的皇后在j列
int b[9];//b[j]=1 表示第j列有皇后了,=0表示第j列没有皇后
int qipan[9][9];//记录棋盘中的数字,有皇后的格子数字为1,没有皇后的格子为0
int ysx[16];//表示从左下到右上的斜线,y=右,s=上,x=斜,总共15条斜线,每条斜线上所有格子 行号+列号=固定值,值范围2至16,
int yxx[16];//表示从左上到右下的斜线,y=右,x=下,x=斜,总共15条斜线,每条斜线上所有格子 行号-列号=固定值 ,值范围7至-7
int i,j,sum;//sum记录多少种可能
void print();
void dfs(int i) //确定第i行皇后位置
{
int j;
for(j=1;j<=8;j++)
{
if(b[j]==0&&ysx[i+j]==0&&yxx[i-j+7]==0)//1.这一列没有皇后,2.这个点并不在某个皇后覆盖的从左下到右上的斜线上,3. 这个点并不在某个皇后覆盖的从左上到右下的斜线上
{
a[i]=j;
b[j]=1;
qipan[i][j]=1;
ysx[i+j]=1;
yxx[i-j+7]=1;
if(i==8)
{
//if(sum<3)
print();
}
else
dfs(i+1);
//以下为回溯
a[i]=0;
b[j]=0;
qipan[i][j]=0;
ysx[i+j]=0;
yxx[i-j+7]=0;
}
}
return;
}
void print()
{
sum++;
int m,n;
cout<<"No. "<<sum<<endl;
for(m=1;m<=8;m++)
{
for(n=1;n<=8;n++)
{
if(qipan[n][m]==1)
cout<<"1"<<" ";
else
cout<<"0"<<" ";
}
cout<<endl;
}
return;
}
int main()
{
dfs(1);
return 0;
}
1214:八皇后
【题目描述】
会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 × 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。
对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2...b8a=b1b2...b8,其中bi为相应摆法中第i行皇后所处的列数。已经知道8皇后问题一共有92组解(即92个不同的皇后串)。
给出一个数b,要求输出第b个串。串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。
【输入】
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数b(1≤b≤92)。
【输出】
输出有n行,每行输出对应一个输入。输出应是一个正整数,是对应于b的皇后串。
【输入样例】
2
1
92
【输出样例】
15863724
84136275a
【推导过程】
只是在判断处、输出处不同,与之前的是一样的
【参考代码】
#include<bits/stdc++.h>
using namespace std;
int a[8][8],ab=0;
int b[1000];
int c[1000];
int n,a1;
bool cheak(int x,int l)
{
for(int i=x;i>=0;i--)
{
if(a[i][l]==1)
{
return 0;
}
}
for(int k=x,c=l;k>=0&&c>=0;k--,c--)
{
if(a[k][c]==1)
{
return 0;
}
}
for(int k=x,c=l;k>=0&&c<8;k--,c++)
{
if(a[k][c]==1)
{
return 0;
}
}
return 1;
}
void fun(int x)
{
int l;
if(x>7)
{
ab++;
if(ab==a1)
{
for(int i=0;i<8;i++)
{
cout<<b[i]+1;
}
cout<<endl;
}
}
else
{
for(l=0;l<8;l++)
{
if(cheak(x,l))
{
a[x][l]=1;
b[x]=l;
fun(x+1);
a[x][l]=0;
}
}
}
}
int main()
{
int a;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a1;
fun(0);
ab=0;
}
return 0;
}
1215:迷宫
【题目描述】
一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n×n的格点组成,每个格点只有2种状态,.
和#
,前者表示可以通行后者表示不能通行。同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到点B,问在不走出迷宫的情况下能不能办到。如果起点或者终点有一个不能通行(为#
),则看成无法办到。
【输入】
第1行是测试数据的组数kk,后面跟着kk组输入。每组测试数据的第11行是一个正整数n(1≤n≤100),表示迷宫的规模是n×n的。接下来是一个n×n的矩阵,矩阵中的元素为.
或者#
。再接下来一行是4个整数ha,la,hb,lb,描述A处在第ha行, 第la列,B处在第hb行, 第lb列。注意到ha,la,hb,lb全部是从0开始计数的。
【输出】
k行,每行输出对应一个输入。能办到则输出“YES”,否则输出“NO”。
【输入样例】
2
3
.##
..#
#..
0 0 2 2
5
.....
###.#
..#..
###..
...#.
0 0 4 0
【输出样例】
YES
NO
【推导过程】
首先,这道题只需要搜索而不需要回溯,这道题只需要查找到终点,能就输出”YES”,不能就输出”NO”,不需要记录。为了使“可以走”与“不能走”形成“true”与“false”,定义ch(char型),先读入ch,判断后存入a[][](0与1的形式)。与其它偏移题一样,定义偏移量数组dx[]{-1,0,1,0}与dy[]{0,-1,0,1}。在输入完数据后,需要进行特判,如果起点或终点就是障碍物,直接输入”NO”; 之后定义标志变量flag,初始化为false。为了防止不走回头路,需要一个标识数组b[][]。没越界、没有障碍物、没走过满足3者才可以走,否则直接失败;如果成功,flag=true。
最后判断——flag=false输出”NO”,flag=true输出“Yes“。(记得用循环!!!)
【参考代码】
#include<bits/stdc++.h>
using namespace std;
int k, n;
char a[105][105]; //地图
int b[105][105]; //标记数组
int d[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; //方向数组
int startx, starty, endx, endy;
bool flag;
void dfs(int x, int y) {
//递归出口
if (x == endx && y == endy) {
cout << "YES" << endl;
flag = true;
return;
}
//递归条件
for (int i = 0; i < 4; i++) {
int nextx = x + d[i][0];
int nexty = y + d[i][1];
if (nextx >= 0 && nexty >= 0 && nextx < n && nexty < n && a[nextx][nexty] == '.' && !b[nextx][nexty]) {
//没越界、没有障碍物、没走过,同时满足三者才可以走
b[nextx][nexty] = 1;
dfs(nextx, nexty);
//b[nextx][nexty] = 0;
}
}
}
int main()
{
cin >> k;
for (int i = 0; i < k; i++) {
//初始化工作
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
//输入地图维度
cin >> n;
//输入地图
for (int row = 0; row < n; row++) {
for (int col = 0; col < n; col++) {
cin >> a[row][col];
}
}
//输入起点终点
cin >> startx >> starty >> endx >> endy;
//特判
if (a[startx][starty] == '#' || a[endx][endy] == '#') { //起点或终点为#
cout << "NO" << endl;
continue;
}
flag = false;
b[startx][starty] = 1;
dfs(startx, starty);
if (flag == false) cout << "NO" << endl;
}
return 0;
}
搜索与回溯典型题目解析相关推荐
- Java实现搜索回溯经典题目
文章目录 前言 搜索框架 经典问题 前言 搜索与回溯是计算机解题中常用的算法,很多问题无法根据某种确定的计算法则来求解,可以利用搜索与回溯的技术求解.回溯是搜索算法中的一种控制策略.它的基本思想是:为 ...
- Leetcode中二叉树中的搜索相关题目解析以及java实现
Leetcode中二叉树中的搜索相关题目解析以及java实现 这一类的题目其实稍微有一些杂,基本就是在二叉树中寻找一些或者某个特定值,题目比较多,我们会通过两道三篇来总结,不过总体来说也基本上就是BF ...
- Mysql窗口函数 (知识点梳理+题目解析+面试实战)(四万字长文,一文读懂,建议收藏后食用)
前言: 本文章是原创50篇时开启的纪念作,之前的文章基本5000字,而本篇约4.5万字,真一篇顶九篇. 窗口函数作为Mysql 8的新特性以及面试笔试的重点,掌握并且进行来练习是非常有必要的.本文章详 ...
- 2022春秋杯联赛 传说殿堂赛道 sql_debug题目解析
2022春秋杯联赛 传说殿堂赛道 sql_debug题目解析 前言 sql_debug sql_debug 题⽬介绍 dsn_from_uri 触发phar反序列化 Linux下PHP内核调试⼩知识 ...
- 搜索与回溯 1215:迷宫
[题目描述] 一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n * n的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行.同时当Extense处在某 ...
- 【搜索与回溯算法】保卫农场(DFS)
[搜索与回溯算法]保卫农场 (Standard IO) 时间限制: 1000 ms 空间限制: 262144 KB 具体限制 题目描述: 农夫John的农场里有很多小山丘,他想要在那里布置一些保镖 ...
- Nuist集训队作业:深度优先搜索(回溯算法)
Nuist集训队第一次作业:深度优先搜索(回溯算法) 引例 深搜基本思想及回溯算法模板 P1706 全排列问题 P1219 八皇后 P1605 迷宫 P1101 单词方阵 小结 引例 国际西洋棋棋手马 ...
- 计算机网络-关于IP地址与子网划分的题目解析
知识笔记 关于子网号全0全1问题: 现在子网号全0全1是可用的,但09年之前因为协议原因不可用全0全1划分子网.根据考研要求可知已经部分高校认定全0全1可以使用,个人认为不确定时以可以用全0全1划分子 ...
- 2015年第六届蓝桥杯C/C++B组省赛题目解析
1.奖券数目 有些人很迷信数字,比如带"4"的数字,认为和"死"谐音,就觉得不吉利. 虽然这些说法纯属无稽之谈,但有时还要迎合大众的需求.某抽奖活动的奖券号码是 ...
最新文章
- 昆仑通态通用版找不到驱动_2021深圳新安西门子伺服驱动电机回收合作共赢
- jQuery/javascript实现简单网页计算器
- LFTP : 一个功能强大的命令行FTP程序
- CVPR2019| 最新CVPR2019论文:含目标检测、分割、深度学习、GAN等领域
- python log模块_Python日志模块-logging
- 一个很好的开源图像处理软件--imageJ (2
- BEGINNING SHAREPOINT#174; 2013 DEVELOPMENT 第9章节--client对象模型和REST APIs概览 client对象模型(CSOM)基础...
- pyqt5 yolov4实现车牌识别系统
- 关于WiFi密码破解的一些心得
- C#之Dispose
- 精通 Spring Boot 42 讲
- Chrome设置--disable-web-security解决跨域问题
- “剧情+综艺” 助推国潮文化破圈
- 两种图像骨架提取算法的研究原理及实现
- 几种比较好看的颜色代码
- 微信朋友圈附近推效果怎么样?
- 人脸识别中的全脸/半脸/中脸
- XSS与字符编码的那些事儿
- 25. Green Living 绿色生活
- android锁屏时间大小,Android 4.4.4 锁屏界面时间大小修改
热门文章
- 防火墙和NAT基础学习
- 企业内部即时通讯工具支持内网私有化部署
- matlab画y x 2,matlab怎么绘制z=sqrt(x^2 y^2)的图像
- (转)PC+运动控制卡的控制方案
- 菜鸟之路---2,简单的勒索病毒分析
- HTTP/2.0 中英文对照
- [Python练习-文件] 多目录下的字幕vtt转srt
- java timewait_time_wait和close_wait产生原因及解决
- Eureka注册发现及Feign调用示例
- Google大数据三大论文-MapReduce--中文翻译