1 条题解

  • 0
    @ 2022-9-20 20:42:36

    之前写了个骗分的bfs“通过”。然后上网查了一下题解,再结合了一下自己的思路终于真真实实地通过了。

    这道题就是bfs,但是有个误区:路径越短,拐弯越少。这是一个反例:

    0 0 0 0
    0 1 1 0
    0 1 0 0
    0 0 0 1
    起点(1,4),终点(4,2)
    

    此时只有两条路径能通往终点。一条是通过最上面那一行,长度7,拐弯2次;一条是往下走“阶梯”形,长度5,拐弯3次。可以看出,并不是路径越短拐弯越少。因此不能求最短路径。

    我们可以发现,从任意一点开始往任意一个方向走一直走到不能再走,期间经过的所有点与起点拐弯次数相同。所以我们可以每搜到一个点就扩展其四个方向的点并记录它们的拐弯次数。在扩展一个点时,若其之前被扩展过,则比较之前的拐弯次数与新的拐弯次数,记录更少的那个

    codecode

    #include <iostream>
    #include <queue>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    struct Point{
        int x,y;
    };
    int n,m,sx,sy,ex,ey,f[1001][1001];
    bool a[1001][1001];
    queue<Point> q;
    const int dx[]={0,0,-1,1};
    const int dy[]={1,-1,0,0};
    void bfs(){
        q.push({sx,sy});
        f[sx][sy]=0;
        while (q.size()){
            Point now=q.front();
            q.pop();
            for (int i=0;i<4;i++){
                int nx=now.x+dx[i];
                int ny=now.y+dy[i];
                while (nx>0&&nx<=n&&ny>0&&ny<=m&&!a[nx][ny]){//向四周扩展
                    if (f[now.x][now.y]+1<f[nx][ny]){//只有当新的拐弯次数更新的拐弯次数更少时才更新
                        if (nx==ex&&ny==ey){
                            cout<<f[now.x][now.y];//注意是输出队首而非队尾的拐弯次数,因为我们把走第一步算成拐弯一次,实际上这不能算
                            exit(0);
                        }
                        q.push({nx,ny});
                        f[nx][ny]=f[now.x][now.y]+1;//队首拐弯
                    }
                    nx+=dx[i];//继续扩展
                    ny+=dy[i];
                }
            }
        }
    }
    int main(){
        memset(f,0x3f,sizeof(f));//注意最初f数组要全部赋值为极大值,这样才能确保第一次更新不会受影响
        cin>>n>>m;
        for (int i=1;i<=n;i++){
            for (int j=1;j<=m;j++){
                cin>>a[i][j];
            }
        }
        cin>>sx>>sy>>ex>>ey;
        bfs();
    }
    

    终于摆脱了虚伪的荣誉

    • @ 2022-10-1 11:40:55
      • [ ] 但是你给出的例子都是一样长的
  • 1

信息

ID
441
时间
1000ms
内存
128MiB
难度
4
标签
递交数
40
已通过
20
上传者