一、走迷宫
给定一个n*m的二维整数数组,用来表示一个迷宫,数组中只包含0或1,其中0表示可以走的路,1表示不可通过的墙壁。
最初,有一个人位于左上角(1, 1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角(n, m)处,至少需要移动多少次。
数据保证(1, 1)处和(n, m)处的数字为0,且一定至少存在一条通路。
输入格式
第一行包含两个整数n和m。
接下来n行,每行包含m个整数(0或1),表示完整的二维数组迷宫。
输出格式
输出一个整数,表示从左上角移动至右下角的最少移动次数。
数据范围
1≤n,m≤100
样例
输入样例:
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出样例:
8
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int a[N][N],v[N][N];//a数组为地图数组,v数组为访问数组
struct point //点坐标
{
int x;
int y;
int step;
};
queue<point> r;//stl中的功能,申请队列r
int dx[4]={0,1,0,-1};//右下左上
int dy[4]={1,0,-1,0};
int main()
{
int m,n;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
//BFS
memset(v,-1,sizeof v);//初始化v数组为未访问-1
point start;//开始的点
start.x=1;
start.y=1;
start.step=0;
r.push(start);//将起点入队
v[1][1]=0;
while(!r.empty())
{
int x=r.front().x,y=r.front().y;//r队列的队首坐标
if(x==n&&y==m)
{
cout<<r.front().step;
break;
}
for(int k=0;k<4;k++)
{
int tx,ty;
tx=x+dx[k];
ty=y+dy[k];
if(a[tx][ty]==0&&v[tx][ty]==-1&&x>0&&x<=n&&y>0&&y<=m)
{
//入队
point temp;//临时结构体变量
temp.x=tx;
temp.y=ty;
temp.step=r.front().step+1;//队首步数加一
r.push(temp);
v[tx][ty]=0;
}
}
r.pop();//拓展完后需将队首元素出队
}
return 0;
}
二、八数码
在一个3×3的网格中,1~8这8个数字和一个“x”恰好不重不漏地分布在这3×3的网格中。
例如:
1 2 3
x 4 6
7 5 8
在游戏过程中,可以把“x”与其上、下、左、右四个方向之一的数字交换(如果存在)。
我们的目的是通过交换,使得网格变为如下排列(称为正确排列):
1 2 3
4 5 6
7 8 x
例如,示例中图形就可以通过让“x”先后与右、下、右三个方向的数字交换成功得到正确排列。
交换过程如下:
1 2 3 1 2 3 1 2 3 1 2 3
x 4 6 4 x 6 4 5 6 4 5 6
7 5 8 7 5 8 7 x 8 7 8 x
现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。
输入格式
输入占一行,将3×3的初始网格描绘出来。
例如,如果初始网格如下所示:
1 2 3
x 4 6
7 5 8
则输入为:1 2 3 x 4 6 7 5 8
输出格式
输出占一行,包含一个整数,表示最少交换次数。
如果不存在解决方案,则输出”-1”。
样例
输入样例:
2 3 4 1 5 x 7 6 8
输出样例
19
1、题目的目标
求最小步数 -> 用BFS
2、移动情况
移动方式:
转以后:a = x + dx[i], b = y + dy[i].
思想:将每一种情况作为1个节点,目标情况即为终点
从初始状况移动到目标情况 —> 求最短路
3、问题
第一点:怎么表示一种情况使其能作为节点?
第二点:如何记录每一个状态的“距离”(即需要移动的次数)?
第三点:队列怎么定义,dist数组怎么定义?
4、解决方案
将 “3*3矩阵” 转化为 “字符串”
如:
所以:
队列可以用 queue<string>
//直接存转化后的字符串
dist数组用 unordered_map<string, int>
//将字符串和数字联系在一起,字符串表示状态,数字表示距离
5、矩阵与字符串的转换方式
#include<bits/stdc++.h>
using namespace std;
int dx[4]={-1,0,1,0};//转移方式
int dy[4]={0,1,0,-1};
int bfs(string start)
{
//定义目标状态
string end="12345678x";
//定义队列和dist数组
queue<string> q;
unordered_map<string,int> dist;//哈希
//初始化队列和dist数组
q.push(start);
dist[start]=0;
while(q.size())
{
string t=q.front();
q.pop();
//记录当前状态的距离,如果是最终状态则返回距离
int distence=dist[t];
if(t==end)
return distence;
//状态转移
int k=t.find('x');//查询x在字符串中的下标,然后转换为在矩阵中的坐标
int x=k/3,y=k%3;
for(int i=0;i<4;i++)
{
int a=x+dx[i],b=y+dy[i];//求转移后x的坐标
//当前坐标没有越界
if(a>=0&&a<3&&b>=0&&b<3)
{
//转移x 从二维坐标转变为一维坐标
swap(t[k],t[a*3+b]);
if(!dist.count(t))
{
dist[t]=distence+1;
q.push(t);
}
//还原状态,为下一种转换情况做准备
swap(t[k],t[a*3+b]);
}
}
}
//无法转换到目标状态,返回-1
return -1;
}
int main()
{
string start;
for(int i=0;i<9;i++)
{
char c;
cin>>c;
start+=c;
}
cout<<bfs(start)<<endl;
return 0;
}