BFS专辑

链接:https://ac.nowcoder.com/acm/contest/1017/A
来源:牛客网

题目描述
Little Tom loves playing games. One day he downloads a little computer game called ‘Bloxorz’ which makes him excited. It’s a game about rolling a box to a specific position on a special plane. Precisely, the plane, which is composed of several unit cells, is a rectangle shaped area. And the box, consisting of two perfectly aligned unit cube, may either lies down and occupies two neighbouring cells or stands up and occupies one single cell. One may move the box by picking one of the four edges of the box on the ground and rolling the box 90 degrees around that edge, which is counted as one move. There are three kinds of cells, rigid cells, easily broken cells and empty cells. A rigid cell can support full weight of the box, so it can be either one of the two cells that the box lies on or the cell that the box fully stands on. A easily broken cells can only support half the weight of the box, so it cannot be the only cell that the box stands on. An empty cell cannot support anything, so there cannot be any part of the box on that cell. The target of the game is to roll the box standing onto the only target cell on the plane with minimum moves.
在这里插入图片描述

The box stands on a single cell
在这里插入图片描述

The box lies on two neighbouring cells, horizontally
在这里插入图片描述

The box lies on two neighbouring cells, vertically
After Little Tom passes several stages of the game, he finds it much harder than he expected. So he turns to your help.

输入描述:
Input contains multiple test cases. Each test case is one single stage of the game. It starts with two integers R and C(3 ≤ R, C ≤ 500) which stands for number of rows and columns of the plane. That follows the plane, which contains Rlines and C characters for each line, with ‘O’ (Oh) for target cell, ‘X’ for initial position of the box, ‘.’ for a rigid cell, ‘#’ for a empty cell and ‘E’ for a easily broken cell. A test cases starts with two zeros ends the input.
It guarantees that
There’s only one ‘O’ in a plane.
There’s either one ‘X’ or neighbouring two 'X’s in a plane.
The first(and last) row(and column) must be ‘#’(empty cell).
Cells covered by ‘O’ and ‘X’ are all rigid cells.
输出描述:
For each test cases output one line with the minimum number of moves or “Impossible” (without quote) when there’s no way to achieve the target cell.

示例1
输入
7 7
#######
#…X###
#…##O#
#…E#
#…E#
#…#
#######
0 0

输出
10

AC代码:

#include<iostream>
#include<queue>
using namespace std;

struct Rec{
    int x, y, lie;
};
char g[510][510];
Rec st, ed;
int n, m;
int movx[4] = {0, 0,-1, 1};
int movy[4] = {-1, 1, 0, 0};
bool valid(int x, int y){
    return x >= 0 && x < n && y >= 0 && y < m;
}

bool valid(Rec next){
    if(!valid(next.x, next.y)) return 0;
    if(g[next.x][next.y] == '#') return 0;
    //如果下一次是立着,且它所在的这个格子不是.的话就返回0
    if(next.lie == 0 && g[next.x][next.y] != '.') return 0;
    //如果下一次是横着,且组成这个盒子的另外一个格子的y值是#的话就返回0
    if(next.lie == 1 && g[next.x][next.y + 1] == '#') return 0;
    //如果下一次是横着,且组成这个盒子的另外一个格子的x值是#的话就返回0
    if(next.lie == 2 && g[next.x + 1][next.y] == '#') return 0;
    return 1;
}
void parse(){
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            if(g[i][j] == 'O') ed.x = i, ed.y = j, g[i][j] = '.';
            else if(g[i][j] == 'X'){
                for(int k = 0; k < 4; k++){
                    int nowx = i + movx[k];
                    int nowy = j + movy[k];
                    if(valid(nowx, nowy) && g[nowx][nowy] == 'X'){
                        //取组成盒子的两个格子中横纵坐标最小的那个代表盒子的开始位置
                        st.x = min(st.x, nowx);
                        st.y = min(st.y, nowy);
                        //k=0,1说明开始盒子一定是横着放
                        //k=2,3说明开始盒子一定是竖着放
                        st.lie = k < 2 ? 1:2;
                        g[i][j] = g[nowx][nowy] = '.';
                        break;
                    }
                    if(g[i][j] == 'X') st.x = i, st.y = j, st.lie = 0;
                }
            }
        }
    }
}

int d[510][510][3];
int next_x[3][4]={{0,-2,0,1},{0,-1,0,1},{0,-1,0,2}};
int next_y[3][4]={{-2,0,1,0},{-1,0,2,0},{-1,0,1,0}};
int next_lie[3][4]={{1,2,1,2},{0,1,0,1},{2,0,2,0}};
queue<Rec>q;
int bfs(){
    //初始化距离数组
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            for(int k = 0; k < 3; k ++) d[i][j][k] = -1;
    while(!q.empty()) q.pop();
    d[st.x][st.y][st.lie] = 0;
    q.push(st);
    while(!q.empty()){
        Rec f = q.front(); q.pop();
        if(f.x == ed.x&&f.y==ed.y&&f.lie==ed.lie)return d[f.x][f.y][f.lie];
        for(int i = 0; i < 4; i++){
            Rec next;
            next.x = f.x + next_x[f.lie][i];
            next.y = f.y + next_y[f.lie][i];
            //cout << next.x << " "<< next.y << end;
            next.lie = next_lie[f.lie][i];
            if(!valid(next)) continue;
            if(d[next.x][next.y][next.lie] == -1){
                d[next.x][next.y][next.lie] = d[f.x][f.y][f.lie] + 1;
                q.push(next);
            }
        }
    }
    return -1;
}

int main(){
    while(cin>>n>>m&&n&&m){
        for(int i = 0; i < n; i++) scanf("%s", g[i]);
        parse();
        int ans = bfs();
        if(ans == -1) puts("Impossible");
        else cout << ans << endl;
    }
    return 0;
}

矩阵距离

题目描述
给定一个N行M列的01矩阵 A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为:
dist(A[i][j],A[k][l]) =|i-k|+|j-l|
输出一个N行M列的整数矩阵B,其中:
B[i][j]=min(1≤x≤N,1≤y≤M,A[x][y]=1)⁡{dist(A[i][j],A[x][y])}
即求与每个位置曼哈顿距离最近的1
N,M≤1000

输入描述:
第一行两个整数n,m。
接下来一个N行M列的01矩阵,数字之间没有空格。
输出描述:
一个N行M列的矩阵B,相邻两个整数之间用一个空格隔开。

示例1
输入
3 4
0001
0011
0110
输出
3 2 1 0
2 1 0 0
1 0 0 1

解题思路

首先,我们明确题目让我们求的是每个点的最小的曼哈顿距离,因此,我们先定义一个d[][]二维数组来存储答案,我们可以以‘1’作为参考点,因为每个‘1’对应的最小曼哈顿距离都是0,我们先初始化这些参考点,然后再将他们加入队列,我们这里自己定义了一个队列,首先我们将所有的参考点都加入到队列中,然后从前往后遍历队列,看看他们周围有无点为0,如果有,就将它的d[i][j]变为原来的d[t.x][t.y]加一,然后将这个点加入到队列中,就相当于洪水灌溉到了这个点,这个点还是可以继续往后去到它周围的一个点,什么时候退出循环呢?显然,我们可以定义一个指针hh,把它开始的位置定义为0,然后每移动到一个新的点就将其加1,直到hh和队列的大小tt相等时,我们才退出循环,这样就能保证原来数组中的每一点都被访问到。

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

const int N = 1010;
char g[N][N];
int d[N][N];
typedef pair<int,int>P;
#define x first
#define y second
int n,m;
P q[N*N];
int dir[] = {1, 0, -1, 0, 0, 1, 0, -1};
void bfs(){
    memset(d, -1, sizeof d);
    int hh = 0, tt = -1;
    for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++){
        if(g[i][j] == '1'){
            d[i][j] = 0;
            q[++tt] = {i, j};
        }
    }
    while(hh <= tt){
        auto t = q[hh++];
        for(int i = 0; i < 4; i++){
            int a = t.x + dir[i], b = t.y + dir[i + 4];
            if(a >= 1 && a <= n && b >= 1 && b <= m && d[a][b] == -1){
                d[a][b] = d[t.x][t.y] + 1;
                q[++tt] = {a, b};
            }
        }
    }
}

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%s", g[i] + 1);
    bfs();
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++)
            printf("%d ", max(d[i][j], 0));
        puts("");
    }

    return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追梦_赤子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值