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; 
} 

posted @ 2024-03-18 22:43  星竹z  阅读(10)  评论(0编辑  收藏  举报