1224. 简单迷宫问题

shwei
/*
    需要注意的是,每个点的权值是不一样的。
    普通的bfs,每个点的权值都相同,也就是每一层之间的距离是一样的,那么第一次搜索到这个点的时候,层次数最小,就是最短距离。
    但是这道题中层次数最小并不一定是距离最小,搜索了5层 ' X ',和搜索了6层 ' . ' 哪个距离短?很明显是6层的距离短。
    所以即便先前已经搜索到了这个点,后面的搜索依然需要将这个点的距离更新。所以我们不需要设vis数组来表示搜索过没有。只
    需要不断的更新直至队列为空就行了。

    题意:走迷宫,求最短路径,上下左右走一格花费1,走到有怪的格子花费2.
    思路:将每一点的坐标和由起点到该点的距离存入结构体.
    由起点开始,将该点存入优先队列,以到起点的距离dis为优先级,每次取出dis最小的,向外扩散。
    相当于第一轮得出所有到起点距离为1的点,第二轮得出所有到起点距离为2的点。
    注意:对普通的最短路问题,由于每个各自的花费相同,因此每次存入的点优先级都相同.
    故不需要使用优先队列,但本题存在有无怪物的区别,每次存入的格子的优先级可能不同,故使用优先队列。
*/

#include<stdio.h>
#include<queue>
#include<iostream>
using namespace std;
char maze[201][201];
int sx, sy, tx, ty;
//左右上下4个方向
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };
int m, n;

struct node {
    int x,  y, dis;
};

bool operator < (const node & a, const node & b) {
    return a.dis > b.dis;
}



void bfs() {
    priority_queue<node> que;
    node st { sx,sy,0 };
    maze[sx][sy] = '#';
    que.push(st);

    while (!que.empty()) {
        node p = que.top();
        que.pop();
        //若已找到则退出
        if (p.x == tx && p.y == ty) {
            cout << p.dis << endl;
            return;
        }
        for (int i = 0; i < 4; ++i) {
            int nx = p.x + dx[i];
            int ny = p.y + dy[i];
            node np{ nx,ny, 0};

            if (nx >= 0 && nx < n&&ny >= 0 && ny < m&&maze[nx][ny] != '#') {
                if (maze[nx][ny] == 'X')
                    np.dis = p.dis + 2;
                else
                    np.dis = p.dis + 1;
                maze[np.x][np.y] = '#';
                que.push(np);

            }
        }
    }
    printf("impossible\n");
}
int main() {
#ifdef LC
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif // LC

    while (cin>>n>>m) {
        for (int i = 0; i < n; i++)
            scanf("%s", maze[i]);
        for(int i=0; i<n; i++)
            for (int j = 0; j < m; j++) {
                if (maze[i][j] == 'S')
                    sx = i, sy = j;
                else if (maze[i][j] == 'T')
                    tx = i, ty = j;
            }
        bfs();
    }
    return 0;
}
爱丽丝_青贝尔克

原版迷宫问题没有怪兽,每个行动的优先级是一样的,而本题要通过怪兽需要两步,优先级产生了区别,
所以在原本bfs解法基础上,将队列改为优先队列即可。

#include <bits/stdc++.h>
using namespace std;
char fk[201][201];
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int sx,sy,gx,gy,n,m;
struct node
{
    int x,y,dis;
};
bool operator < (const node& a,const node& b)
{
    return a.dis>b.dis;
}
void bfs()
{
    priority_queue<node> que;
    node St{sx,sy,0};
    fk[sx][sy]='#';
    que.push(St);
    while (!que.empty())
    {
        node p =que.top();
        que.pop();
        if (p.x==gx&&p.y==gy)
        {
            cout<<p.dis<<endl;
            return ;
        }
        for (int i=0;i<4;++i)
        {
            int nx = p.x+dx[i],ny=p.y+dy[i];
            node tmp{nx,ny};
            if (nx>=0&&nx<n&&ny>=0&&ny<m&&fk[nx][ny]!='#')
            {
                if (fk[nx][ny]=='X')
                    tmp.dis=p.dis+2;
                else
                    tmp.dis=p.dis+1;
                fk[nx][ny]='#';
                que.push(tmp);
            }
        }
    }
    cout<<"impossible"<<endl;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    #endif
    while (cin>>n>>m)
    {
        for (int i=0;i<n;++i)
            for (int j=0;j<m;++j)
            {
                cin>>fk[i][j];
                if (fk[i][j]=='S')
                    sx=i,sy=j;
                else if(fk[i][j]=='T')
                    gx=i,gy=j;
            }
        bfs();
    }
}
scott_ch

用队列bfs,遇到怪兽就pop掉再push进去。这样就可以在怪物那里停留一步。

clysto
#include <bits/stdc++.h>

using namespace std;

int n, m;
char M[200][200];

struct point {
    int x, y;
    int v;

    friend bool operator<(const point &a, const point &b) {
        return a.v > b.v;
    }
};


int main() {
    while (cin >> n >> m) {
        int x, y, tx, ty;
        // read the map
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                cin >> M[i][j];
                if (M[i][j] == 'S') {
                    x = i;
                    y = j;
                } else if (M[i][j] == 'T') {
                    tx = i;
                    ty = j;
                }
            }
        }

        // bfs
        priority_queue<point> q;
        q.push(point{x, y, 0});
        M[x][y] = '#';
        while (!q.empty()) {
            auto p = q.top();
            q.pop();
            x = p.x;
            y = p.y;
            if (x == tx && y == ty) {
                cout << p.v << endl;
                goto tag;
            }

            if (x - 1 >= 0 && M[x - 1][y] != '#') {
                q.push(point{x - 1, y, p.v + (M[x - 1][y] == 'X' ? 2 : 1)});
                M[x - 1][y] = '#';
            }
            if (y + 1 < m && M[x][y + 1] != '#') {
                q.push(point{x, y + 1, p.v + (M[x][y + 1] == 'X' ? 2 : 1)});
                M[x][y + 1] = '#';
            }
            if (x + 1 < n && M[x + 1][y] != '#') {
                q.push(point{x + 1, y, p.v + (M[x + 1][y] == 'X' ? 2 : 1)});
                M[x + 1][y] = '#';
            }
            if (y - 1 >= 0 && M[x][y - 1] != '#') {
                q.push(point{x, y - 1, p.v + +(M[x][y - 1] == 'X' ? 2 : 1)});
                M[x][y - 1] = '#';
            }
        }
        cout << "impossible" << endl;
        tag:;
    }

    return 0;
}
10152130146

states怎么有人时间0内存0的?
代码竟然有23KB,这是什么神奇的方法?
[em:08][em:08][em:08][em:08][em:08][em:08]

10185101135

注意读入一组新的数据后要清空优先队列。

10152130220

题解
如果是原始的迷宫问题BFS,我们走过一个点P以后就把它标记掉,之后就不会走了,但这题这样做就错了,因为可能之后会有一个到P更短的路径,只是这个状态更晚出来却因为你把P标记掉了,而无法得到这个更优答案。实际上是因为原始迷宫问题每个状态所在的层数就是步数,但因为这里有怪兽的存在,层数和步数可能并不一致,也就是说如果我们某一步选择了打怪兽,那么这个新状态实际上在搜索树里是在当前状态的下两层的,而不是下一层。
下面举个例子



SMMMT
这里表示可以走的地方,M表示怪兽,ST表示起点和终点,如果我们第一个拓展的节点是M,第二个节点是,第一层结束。接着从第一层的节点扩展,第三个是M,第四个是,第五也是,这样第二层结束。一直这样进行下去,我们会发现第一个到达T的状态是从最后那个M过来的,结果是7,然后我们就把终点标记掉,之后的所有拓展就会跳过这个点了。但事实上,如果只从*从,最短是6,也就是说有一个更优的状态,但如果我们把走过的点都标记点之后不走,会错过这个更优状态。解决方法就是改用一个数组存储到某一点的最短步数,不断地去更新这个最短步数,而不是直接走过某个点之后就不走这个点了。

include

include

include

include

include

include

define REP(i,n) for(int i=0;i<n;i++)

using namespace std;
struct node {
int x,y,step;
node(int x,int y,int step):x(x),y(y),step(step) {}
node() { }
};
const int maxn = 200+5;
const int dx[4] = {1,-1,0,0};
const int dy[4] = {0,0,1,-1};
int t;
string grid[maxn];
queue Q;
int vis[maxn][maxn],n,m;
int MIN[maxn][maxn];
node st,tr;

int main() {
while(~scanf(“%d%d”,&n,&m)) {
REP(i,n) {
cin >> grid[i];
REP(j,m) {
if (grid[i][j]==’S’) st = node(i,j,0);
if (grid[i][j]==’T’) tr = node(i,j,0);
}
}
while (!Q.empty()) Q.pop();
Q.push(st);
memset(vis,0,sizeof(vis));
memset(MIN,0xff,sizeof(MIN));
vis[st.x][st.y] = 1;
MIN[st.x][st.y] = 0;
int ans = -1,flag = 0;
while (!Q.empty()) {
node u = Q.front(); Q.pop();
REP(k,4) {
int tx = u.x+dx[k],ty=u.y+dy[k];
if (tx<0 || tx>=n || ty<0 || ty>=m || grid[tx][ty]==’#’) continue;
int cost = u.step + (grid[tx][ty]==’X’?2:1);

            if (!(MIN[tx][ty] == -1 || MIN[tx][ty] !=-1 && cost<MIN[tx][ty])) continue;

            MIN[tx][ty] = cost;
            Q.push(node(tx,ty,cost));
        }
    }
    ans = MIN[tr.x][tr.y];
    if (ans==-1) cout << "impossible" <<endl;
    else cout <<ans <<endl;
}

}

solofandy_

禁止 带有不健康的话语
同题

你当前正在回复 博客/题目
存在问题!