BFS记忆化搜索---标记
迷宫(洛谷)
题目描述
给定一个 \(N \times M\) 方格的迷宫,迷宫里有 \(T\) 处障碍,障碍处不可通过。
在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。
输入格式
第一行为三个正整数 \(N,M,T\),分别表示迷宫的长宽和障碍总数。
第二行为四个正整数 \(SX,SY,FX,FY\),\(SX,SY\) 代表起点坐标,\(FX,FY\) 代表终点坐标。
接下来 \(T\) 行,每行两个正整数,表示障碍点的坐标。
输出格式
输出从起点坐标到终点坐标的方案总数。
样例 #1
样例输入 #1
2 2 1
1 1 2 2
1 2
样例输出 #1
1
提示
对于 \(100\%\) 的数据,\(1 \le N,M \le 5\),\(1 \le T \le 10\),\(1 \le SX,FX \le n\),\(1 \le SY,FY \le m\)。
解
- 这个题的巧妙之处在于存储状态
- 连通性就只需要存横纵坐标,但是这个需要存状态
- used数组是当前搜索路径上的一个状态,因为这里需要方案数,需要状态
#include <iostream>
#include<queue>
#include<cstring>
using namespace std;
bool st[6][6];
int sx, sy, tx, ty;
int n, m, T;
int ans;
int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
struct node
{
int x, y;
int used[6][6];
}arr;
void bfs()
{
queue<node> q;
arr.x = sx, arr.y = sy;
arr.used[sx][sy] = 1;
q.push(arr);
while (!q.empty())
{
auto t = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int a = t.x + dx[i], b = t.y + dy[i];
if (a <= 0 || a > n || b <= 0 || b > n) continue;
if (st[a][b]) continue;
if (t.used[a][b]) continue;
if (a == tx && b == ty)
{
ans++;
continue;
}
// 当前路径的横纵坐标及状态
arr.x = a;
arr.y = b;
memcpy(arr.used, t.used, sizeof(t.used)); // 将当前路径的上一次状态拷贝,然后继续标记,在入队
arr.used[a][b] = 1;
q.push(arr);
}
}
}
int main()
{
cin >> n >> m >> T;
cin >> sx >> sy >> tx >> ty;
while (T--)
{
int x, y;
scanf("%d%d", &x, &y);
st[x][y] = true;
}
bfs();
printf("%d", ans);
return 0;
}
没存状态的WA版本
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
typedef pair<int, int>PII;
int g[10][10];
int n, m, t;
bool st[10][10];
int cnt = 0;
void bfs(int x1, int y1, int x2, int y2)
{
int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 };
queue<PII>q;
q.push({ x1,y1 });
st[x1][y1] = true;
while (q.size())
{
auto t = q.front();
q.pop();
int x = t.first, y = t.second;
for (int i = 0;i < 4;i++)
{
x += dx[i], y += dy[i];
if (x > 0 && x <= x2 && y > 0 && y <= y2 && g[x][y] == 0 && !st[x][y])
{
q.push({ x,y });
st[x][y] = true;
if (x == x2 && y == y2)
cnt++;
}
}
}
}
int main()
{
memset(g, 0, sizeof g);
cin >> n >> m >> t;
int x1, x2, y1, y2;
cin >> x1 >> y1 >> x2 >> y2;
while (t--)
{
int x, y;
cin >> x >> y;
g[x][y] = 1;
}
bfs(x1, y1, x2, y2);
return 0;
}
//错误的,打个底,备份以后长记性
DFS版本---偷的
#include <iostream>
#include <cstdio>
using namespace std;
bool G[15][15],VIS[15][15];//G为总地图,VIS记录是否访问
int n,m,d[5]={-1,0,1,0,-1};//方向不解释
int nx,ny,ex,ey,CNT;
//nx,ny起点坐标;ex,ey终点坐标,CNT路径条数
void dfs(int x,int y)
{
if (x ==ex&&y ==ey)//如果到终点
{
CNT++;//路径加一
return;//回去继续查找
}
for (int k=0;k<4;k++)
{
int l=x+d[k];int r=y+d[k+1];
if (l>=1&&r>=1&&l<=n&&r<=m&&!G [l][r]&&!VIS [l][r])
{
VIS [l][r]=true;//标记为已访问
dfs (l,r);
VIS [l][r]=false;//回溯
}
}
return;
}
int main ()
{
int t,zx,zy;
cin>>n>>m>>t>>nx>>ny>>ex>>ey;
G[nx][ny]=true; //这就是许多人(我)40分的原因
//因为dfs函数里并没有将起点设为已访问
//所以在后面的访问里,可能访问起点许多次
//所以你的答案可能比标准答案多
while(t--)
{
cin>>zx>>zy;
G[zx][zy]=true;//设为障碍
}
dfs (nx,ny);//从起点开始寻找
cout<<CNT;
return 0;
}