首页 > 其他分享 >广度优先搜索 洛谷P1443马的遍历(bfs超时问题)

广度优先搜索 洛谷P1443马的遍历(bfs超时问题)

时间:2024-05-22 16:20:29浏览次数:29  
标签:洛谷 P1443 int direct bfs xx ans uy ux

广度优先搜索

洛谷P1443

这里先介绍一下广度优先搜索:
广度优先搜索就是先将第一步可能的步骤全部记录,遍历过后,再将由第一步到达的第二步全部记录并遍历,直到最后全部遍历。

而此题要求我们求得最少步数,广度优先就能够达到最少步数的要求,因为广度优先是先通过搜索所有可能的第n步才进行第n+1步

这里还涉及到bfs的超时问题,后面会细说

广度优先遍历模板

void bfd(){
	q.push(初始状态);
	while(!q.empty()) {
		STATE u = q.front(); // 记录目前的状态
		for(目前状态能达到的下一步){
			if(v未被未访问过){
				q.push(v);
			}
		}
	}
}

那其实用这个模板就已经足够解决这个问题了

下面就是半成品代码(为啥不是成品

#include<bits/stdc++.h>
using namespace std;
struct pos{
    int x, y;
    int now;
};
queue<pos> q;
int direct[8][2] = {{2,1}, {1,2}, {2,-1}, {1,-2}, {-1,-2}, {-2,-1}, {-2,1}, {-1,2}};
int n, m, x_0, y_0;
int ans[405][405];
bool check(int i, int x, int y) {
    if(direct[i][0] + x > n || direct[i][1] + y > m) return false;
    if(direct[i][0] + x < 1 || direct[i][1] + y < 1) return false;
    return true;
}
int main() {
    memset(ans, -1, sizeof(ans));
    cin >> n >> m >> x_0 >> y_0;
    struct pos primary;
    primary.x = x_0; primary.y = y_0; primary.now = 0;
    q.push(primary);
    while(!q.empty()) {
        int ux = q.front().x;
        int uy = q.front().y;
        int unow = q.front().now;
        ans[ux][uy] = unow;
        for(int i = 0; i < 8; i++) {
            if(check(i, ux, uy) && ans[ux+direct[i][0]][uy+direct[i][1]] == -1) {
                struct pos temp;
                temp.x = ux+direct[i][0]; temp.y = uy+direct[i][1];
                temp.now = unow + 1;
                q.push(temp);
            }
        }
        q.pop();
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            printf("%-5d", ans[i][j]);
        }
        printf("\n");
    }
    system("pause");
}

超时问题

上面的代码可以解决一些数据小的用例,但是数据过大就会超时(我就过了两个用例

那为啥会超时呢

很容易想到,超时一般是遍历重复导致的(枚举是重复最多的)

有人可能会说,上面代码中if(check(i, ux, uy) && ans[ux+direct[i][0]][uy+direct[i][1]] == -1)不是已经有了判断重复吗

那我们想一下这种情况,3×3的棋盘,从(1,1)开始

0 xx xx
xx xx xx
xx xx xx

有两个位置可走

0 xx xx
xx xx 1
xx 1 xx

第三行第二列(3,2)遍历到这里时,可以走到(1,1)这个位置,但由于已经ans[1][1]已经被赋值0,所以没有把(1,1)增加到队列中

第二行第三列(2,3)遍历到这里时,可以走到(1,1)这个位置,但由于已经ans[1][1]已经被赋值0,所以没有把(1,1)增加到队列中

这就是 ans[ux+direct[i][0]][uy+direct[i][1]] == -1限制条件的作用,但我们想另一种情况

xx xx xx xx xx
xx xx xx xx xx
xx xx 1 xx xx
0 xx xx xx YYYY
xx xx 2 xx xx
xx xx xx xx xx
xx xx xx xx xx

1和2为同一层,即步数相等,这里的1和2都能走到YYYY这个位置,先遍历1,然后将其能够达到的下一步(1的下一步)加入队列中,再遍历2,然后将其能够达到的下一步(2的下一步)加入队列中

这时我们队列中就是 1 2(1的下一步)(2的下一步)这四部分

但是我们想一想,YYYY是否同时在(1的下一步)和(2的下一步)呢,答案是在。

YYYY还没被遍历到,也就是它的ans还未赋值,2的下一步遍历就已经把它加入到队列中了,虽然不会有二次赋值,但会增加搜索空间,如果数据足够大,就会有很多搜索重复,所以我们需要增加一个是否已经被加入队列的判断(增加了一个flag二维数组)。

下面就是AC代码

#include<bits/stdc++.h>
using namespace std;
struct pos{
    int x, y;
    int now;
};
queue<pos> q;
int direct[8][2] = {{2,1}, {1,2}, {2,-1}, {1,-2}, {-1,-2}, {-2,-1}, {-2,1}, {-1,2}};
int n, m, x_0, y_0;
int ans[405][405],flag[405][405];
bool check(int i, int x, int y) {
    if(direct[i][0] + x > n || direct[i][1] + y > m) return false;
    if(direct[i][0] + x < 1 || direct[i][1] + y < 1) return false;
    return true;
}
int main() {
    memset(ans, -1, sizeof(ans));
    memset(flag, 0, sizeof(flag));
    cin >> n >> m >> x_0 >> y_0;
    struct pos primary;
    primary.x = x_0; primary.y = y_0; primary.now = 0;
    q.push(primary);
    while(!q.empty()) {
        int ux = q.front().x;
        int uy = q.front().y;
        int unow = q.front().now;
        ans[ux][uy] = unow;
        for(int i = 0; i < 8; i++) {
            if(check(i, ux, uy) && ans[ux+direct[i][0]][uy+direct[i][1]] == -1 && !flag[ux+direct[i][0]][uy+direct[i][1]]) {
                struct pos temp;
                temp.x = ux+direct[i][0]; temp.y = uy+direct[i][1];
                flag[temp.x][temp.y] = 1;
                temp.now = unow + 1;
                q.push(temp);
            }
        }
        q.pop();
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            printf("%-5d", ans[i][j]);
        }
        printf("\n");
    }
    system("pause");
}

标签:洛谷,P1443,int,direct,bfs,xx,ans,uy,ux
From: https://www.cnblogs.com/rjxq/p/18206506

相关文章

  • 深度优先搜索 洛谷P1219八皇后
    深度优先搜索洛谷P1219这是一道经典的深度优先搜索问题,深度优先搜索可用以下模板:voiddfs(intdepth){ if(达到边界){ 记录解 } for(枚举在depth这一深度,能够使用的解){ if(解可行){ 记录解(记录已经被使用) dfs(depth+1) 恢复解(恢复原状) } }}题目要求我们......
  • 二分答案 洛谷2440木材加工
    二分答案题目详见洛谷P2440木材加工分享一下自己新学习的二分答案的方法,开始可能有点奇怪为啥这样能做,但其实思路很简单。起始思路题目要求我们求最大的分解长度,所以我(们)最开始想的肯定是从大到小(求最大值)枚举答案,看看是否满足,满足不了就加1。但这样暴力肯定是会超时的,那我们......
  • 洛谷 P4383 [八省联考 2018] 林克卡特树
    原题等价于在树上选出\(k+1\)条不相交链,最大化边权和。树形DP。设\(f_{u,k,0/1/2}\)表示在\(u\)的子树中选了\(k\)条链,\(u\)的度数为\(0,1,2\)的最大边权和。注意到状态里缺了链退化为单个点的情况,可以把它放到\(f_{u,k,2}\)中(相当于自环)。转移时分讨一......
  • 洛谷 P10512 序列合并
    哭死,比赛的时候完全想歪了,想的是考虑一次合并能造成多大的贡献,按照贡献排序然后合并。这样做只能考虑局部造成的贡献,然而最后算的时候要考虑整体,所以并不是很对。正着想没有思路就可以倒着想,考虑枚举答案。合并k次,意味着最后是n-k个数。经典从二进制高位到低位考虑,考虑这一位(假......
  • Solution -「洛谷 P8477」 「GLR-R3」春分 下界证明?!
      前情提要:在「洛谷P8477」「GLR-R3」春分中,我们给出了\(\frac{7}{6}n\pm\mathcalO(1)\)的解法,但没能给出相关的下界证明。现在我们尝试给出一个未完全完成的下界证明。  为方便描述,我们综合链接中题意和某个“通俗”的题意,称隔板为“板”,称溶液为“人”。  这个......
  • 「杂题乱刷」洛谷 P10467
    题目链接P10467[CCC2007]SnowflakeSnowSnowflakes解题思路字符串哈希板子题。思路就是我们给每个数列的所有排列都哈希一个值,然后判断是否有不同的数列的哈希值相同,如果有,就输出Twinsnowflakesfound.,否则就输出Notwosnowflakesarealike.。参考代码这里使用双哈......
  • 「杂题乱刷」洛谷 P10468 兔子与兔子
    题目链接P10468兔子与兔子解题思路字符串哈希板子题。思路就是我们给字符串的每一个前缀和后缀都用一种特定的方式使其变为一个值,比如取一个乘数和模数,可以证明这样出错的概率极低。参考代码这里使用自然溢出三哈希。#include<bits/stdc++.h>usingnamespacestd;#defin......
  • 洛谷题单指南-动态规划3-P1220 关路灯
    原题链接:https://www.luogu.com.cn/problem/P1220题意解读:按坐标顺序排列1~n个路灯,每个路灯有不同的功耗,老张从位置c开始关灯,第一时间关掉c位置的灯,每次关掉一个灯之后,可以往右走、也可以往左走关下一个灯,老张速度是1m/s,求所有灯都关掉所消耗的最少功耗。解题思路:由题意分析,关......
  • 洛谷题单指南-动态规划3-P4342 [IOI1998] Polygon
    原题链接:https://www.luogu.com.cn/problem/P4342题意解读:环中节点表示数字,边表示运算符,可以任意断一条边,其余节点两两按边的符号计算,求结果的最大值,以及最大值是断开那些边可以得到。解题思路:题意中有几个个关键信息:环形,节点数为n,边数为n任意断一条边,即可以从任意节点开始,......
  • 洛谷题单指南-动态规划3-P1070 [NOIP2009 普及组] 道路游戏
    原题链接:https://www.luogu.com.cn/problem/P1070题意解读:1~n个环形机器人工厂,相邻工厂之间的道路是1~n,每个时刻可以从任意工厂购买机器人,走不超过p时间,不同工厂购买机器人花费不同的金币,不同时刻走到不同道路也能得到不同的金币,问一共m时间,最多可以得到多少金币(需减去购买机器人......