第二届ACC(AcWing Cup)全国联赛 C4943. 方格迷宫

题意

题目大意就是给定一个地图,给定一个起点和终点,要求我们以最小步数到达终点,其中不可以落入陷阱并且每步可以走 1 − − k 步 题目大意就是给定一个地图,给定一个起点和终点,要求我们以最小步数到达终点,其中不可以落入陷阱并且每步可以走1--k步 题目大意就是给定一个地图,给定一个起点和终点,要求我们以最小步数到达终点,其中不可以落入陷阱并且每步可以走1k

思路

很明显是个 b f s 裸题 很明显是个bfs裸题 很明显是个bfs裸题
但要加点特殊的处理,因为每次都走 1 − k 步,然后时间复杂度会是 O ( n m k ) 但要加点特殊的处理,因为每次都走1-k步,然后时间复杂度会是O(nmk) 但要加点特殊的处理,因为每次都走1k步,然后时间复杂度会是O(nmk)
这样会超时,而且不可以用 b o o l s t [ ] [ ] 数组来判断是否遍历过,因为这样的话,前面遍历的点会对后面遍历的点产生影响,具体影响看例子 这样会超时,而且不可以用bool st[][]数组来判断是否遍历过,因为这样的话,前面遍历的点会对后面遍历的点产生影响,具体影响看例子 这样会超时,而且不可以用boolst[][]数组来判断是否遍历过,因为这样的话,前面遍历的点会对后面遍历的点产生影响,具体影响看例子


4 4 4
…#
.#.#

##…
1 1 3 4


图解
在这个例子中我们可以看到,第一步被更新的是第一行和第一列标红的1,然后第二步是第三列黑色的2和第三行第二个绿色的二,这时候我们如果用bool st[][]数组来判断的话就break了,因为第三行第三列的2被第一行第一列的那个格子更新过了,这时候就得从第三行第三列开始更新终点了,这样终点的步数就是3了,也就是错了,所以我们不可以用bool st[][]来标记是否来过,在这个情况下我们应该继续用第三行第一列的红1继续更新这一行,这个博客主要就是用来记录下这个bug!!!找了很久才找到,以后知道了,原来bfs中找最短路不可以用bool st[][]还是得需要step[][],还有部分细节写道代码注释里面了

ac代码

#include
using namespace std;
const int N = 1010 + 10;

#define x first
#define y second

typedef pair<int, int> pii;

int n, m, k;
char a[N][N];
int step[N][N];
int s1, d1, s2, d2;
//一个究极bug,就是在bfs过程中之前的路径判断会对之后的产生影响,按照st数组做法

bool check(int xx, int yy, int x, int y)
{
    if(x < 1 || x > n || y < 1 || y > m) return false;
    if(step[x][y] == step[xx][yy]) return false;//这一句话是避免点重复判断,及时break
    if(a[x][y] == '#') return false;
    return true;
}

int bfs()
{
    queue<pii> q;
    q.push({s1, d1});
    int dx[5] = {0, 0, 1, -1};
    int dy[5] = {1, -1, 0, 0};
    memset(step, 0x3f, sizeof(step));
    step[s1][d1] = 0;
    while(q.size())
    {
        pii t = q.front();
        q.pop();
        if(t.x == s2 && t.y == d2)
        {
            return step[s2][d2];
        }
            for(int i = 0; i < 4; i ++)
            {
                for(int p = 1; p <= k; p ++)
                {
                    int tx = t.x + p*dx[i];
                    int ty = t.y + p*dy[i];
                    if(check(t.x, t.y, tx, ty))
                    {
                        //加上这一句话就把时间复杂度降到了O(n*m)
                        //因为bfs中第一次到的点就是最小距离的,所以每个点只会进一次队列
                        if(step[tx][ty] > step[t.x][t.y] + 1)
                        {   
                            step[tx][ty] = step[t.x][t.y] + 1;
                            q.push({tx, ty});
                        }
                    }
                    else
                    break;  
                }   
            }
    }
    return -1;
}


int main()
{
    cin >> n >> m >> k;
    
    for(int i = 1; i <= n; i ++)
    {
        scanf("%s", (a[i]+1));
    }
    cin >> s1 >> d1 >> s2 >> d2;
    int res = bfs();
    printf("%d\n", res);
    
    return 0;
}

链接

点击跳转

你可能感兴趣的:(比赛题解,算法)