0
点赞
收藏
分享

微信扫一扫

搜索专题(BFS、DFS)持续更新 —— 洛谷题目

weipeng2k 2022-01-20 阅读 53

搜索篇 ——洛谷

一、马的遍历

题目链接:P1443 马的遍历 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

有一个 n * m 的棋盘,在某个点 (x, y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。(中国象棋里面的马,不知道怎么走的小伙伴可以百度)。

输入格式

输入只有一行四个整数,分别为 n, m, x, y。

输出格式

一个 n * m 的矩阵,代表马到达某个点最少要走几步(左对齐,宽 5 格,不能到达则输出 −1)。

输入输出样例

输入 #1

3 3 1 1

输出 #1

0    3    2    
3    -1   1    
2    1    4    

数据规模

对于全部的测试点,保证 1 ≤ x ≤ n ≤ 400, 1 ≤ y ≤ m ≤ 400。
#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

typedef pair<int,int> PII;
const int N = 500;
const int dx[8] = {-1,1,-1,1,-2,2,-2,2};
const int dy[8] = {2,2,-2,-2,1,1,-1,-1};
int vis[N][N];
int step[N][N];

int main(){
    int n,m,sx,sy; cin >> n >> m >> sx >> sy;
    queue<PII> que;
    memset(step,-1,sizeof step); memset(vis,0,sizeof vis);
    vis[sx][sy] = 1, step[sx][sy] = 0;
    que.push({sx,sy});
    while(!que.empty()){
        PII temp = que.front(); que.pop();
        for(int i = 0; i < 8; i++){
            int nx = dx[i] + temp.first, ny = dy[i] + temp.second;
            if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny]) continue;
            step[nx][ny] = step[temp.first][temp.second] + 1;
            que.push({nx,ny});
            vis[nx][ny] = 1;
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++)
            printf("%-5d",step[i][j]);
        printf("\n");
    }
    return 0;
}

二、好奇怪的游戏

题目链接:P1747 好奇怪的游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

爱与愁大神坐在公交车上无聊,于是玩起了手机。一款奇怪的游戏进入了爱与愁大神的眼帘:***(游戏名被打上了马赛克)。这个游戏类似象棋,但是只有黑白马各一匹,在点x1,y1和x2,y2上。它们得从点x1,y1和x2,y2走到1,1。这个游戏与普通象棋不同的地方是:马可以走“日”,也可以像象走“田”。现在爱与愁大神想知道两匹马到1,1的最少步数,你能帮他解决这个问题么?

输入格式

第1行:两个整数x1,y1

第2行:两个整数x2,y2

输出格式

第1行:黑马到1,1的步数

第2行:白马到1,1的步数

输入输出样例

输入 #1

12 16
18 10

输出 #1

8 
9

数据范围

100%数据:x1,y1,x2,y2<=20

#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

typedef pair<int,int> PII;
const int N = 60;
const int dx[] = {-1,1,-1,1,-2,2,-2,2,2,2,-2,-2};
const int dy[] = {2,2,-2,-2,1,1,-1,-1,-2,2,-2,2};

int vis[N][N];

struct Node {
    int x, y, step;
    Node(int x, int y, int step){
        this->x = x;
        this->y = y;
        this->step = step;
    }
};

int bfs(int sx, int sy){
    queue<Node> que;
    que.push(Node(sx, sy, 0));
    vis[sx][sy] = 1; 
    while(!que.empty()){
        int x = que.front().x, y = que.front().y, step = que.front().step;
        que.pop();
        for(int i = 0; i < 12; i++){
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 1 || nx > 50 || ny < 1 || ny > 50 || vis[nx][ny]) continue;
            if(nx == 1 && ny == 1) return step + 1;
            que.push(Node(nx, ny, step + 1));
            vis[nx][ny] = 1;
        }
    }
}

int main(){
    int sx,sy;
    cin >> sx >> sy;
    cout << bfs(sx,sy) << endl;
    memset(vis,0,sizeof(vis));
    cin >> sx >> sy;
    cout << bfs(sx,sy) << endl;
    return 0;
}

三、离开中山路

题目链接:P1746 离开中山路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

爱与愁大神买完东西后,打算坐车离开中山路。现在爱与愁大神在x1,y1处,车站在x2,y2处。现在给出一个n×n(n<=1000)的地图,0表示马路,1表示店铺(不能从店铺穿过),爱与愁大神只能垂直或水平着在马路上行进。爱与愁大神为了节省时间,他要求最短到达目的地距离(a[i][j]距离为1)。你能帮他解决吗?

输入格式

第1行:一个数 n

第2行~第n+1行:整个地图描述(0表示马路,1表示店铺,注意两个数之间没有空格)

第n+2行:四个数 x1,y1,x2,y2

输出格式

只有1行:最短到达目的地距离

输入输出样例

输入 #1复制

3
001
101
100
1 1 3 3

输出 #1

4

数据范围

20%数据: n <= 100

100%数据:n <= 1000

#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

typedef pair<int,int> PII;
const int N = 1e3+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};


int vis[N][N];
int step[N][N];
char g[N][N];
int n, sx, sy, ex, ey;; 

int bfs(){
    queue<PII> que;
    que.push({sx,sy});
    vis[sx][sy] = 1;
    while(!que.empty()){
        int x = que.front().first, y = que.front().second;
        que.pop();
        
        for(int i = 0; i < 4; i++){
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 1 || nx > n || ny < 1 || ny > n || vis[nx][ny] || g[nx][ny] == '1') continue;
            vis[nx][ny] = 1;
            que.push({nx,ny});
            step[nx][ny] = step[x][y] + 1; 
            if(nx == ex && ny == ey) return step[nx][ny];
        }
    }
    return -1;
}

int main(){
    cin >> n;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            cin >> g[i][j];
    cin >> sx >> sy >> ex >> ey;

    cout << bfs() << endl;
    return 0;
}

四、Mzc和男家丁的游戏

题目链接:P2298 Mzc和男家丁的游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

mzc家很有钱(开玩笑),他家有n个男家丁(做过上一弹的都知道)。他把她们召集在了一起,他们决定玩捉迷藏。现在mzc要来寻找他的男家丁,大家一起来帮忙啊!

由于男家丁数目不多,再加上mzc大大的找人【laopo】水平很好,所以一次只需要找一个男家丁。

输入格式

第一行有两个数n,m,表示有n行m列供男家丁躲藏,

之后n行m列的矩阵,‘m‘表示mzc,‘d’表示男家丁,‘#’表示不能走,‘.‘表示空地。

输出格式

一行,若有解:输出一个数step,表示找到男家丁的最短移动次数。

若无解:输出“No Way!”。

输入输出样例

输入 #1

5 6
.#..#.
....#.
d.....
#####.
m.....

输出 #1

12

数据范围

3 < = m, n <= 2000

由于mzc大大十分着急,所以他只能等待1S。

#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

typedef pair<int,int> PII;
const int N = 2e3+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};

int vis[N][N];
char g[N][N];
int n, m, sx, sy, ex, ey;; 

struct Node {
    int x, y, step;
    Node(int x, int y, int step){
        this->x = x;
        this->y = y;
        this->step = step;
    }
};

int bfs(){
    queue<Node> que;
    que.push(Node(sx, sy, 0));
    vis[sx][sy] = 1;
    while(!que.empty()){
        int x = que.front().x, y = que.front().y, step = que.front().step;
        que.pop();

        for(int i = 0; i < 4; i++){
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny] || g[nx][ny] == '#') continue;
            vis[nx][ny] = 1;
            que.push(Node(nx, ny, step + 1));
            if(nx == ex && ny == ey) return step + 1;
        }
    }
    return -1;
}

int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++){
            cin >> g[i][j];
            if(g[i][j] == 'm') sx = i, sy = j;
            if(g[i][j] == 'd') ex = i, ey = j;
        }

    int ans = bfs();
    if(ans == -1) cout<<"No Way!"<<endl;
    else cout << ans << endl;
    return 0;
}

五、血色先锋队

题目链接:P1332 血色先锋队 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

军团是一个 nn 行 mm 列的矩阵,每个单元是一个血色先锋军的成员。感染瘟疫的人,每过一个小时,就会向四周扩散瘟疫,直到所有人全部感染上瘟疫。你已经掌握了感染源的位置,任务是算出血色先锋军的领主们感染瘟疫的时间,并且将它报告给巫妖王,以便对血色先锋军进行一轮有针对性的围剿。

输入格式

第 11 行:四个整数 nn,mm,aa,bb,表示军团矩阵有 nn 行 mm 列。有 aa 个感染源,bb 为血色敢死队中领主的数量。

接下来 aa 行:每行有两个整数 xx,yy,表示感染源在第 xx 行第 yy 列。

接下来 bb 行:每行有两个整数 xx,yy,表示领主的位置在第 xx 行第 yy 列。

输出格式

第 11 至 bb 行:每行一个整数,表示这个领主感染瘟疫的时间,输出顺序与输入顺序一致。如果某个人的位置在感染源,那么他感染瘟疫的时间为 00。

输入输出样例

输入 #1

5 4 2 3
1 1
5 4
3 3
5 3
2 4

输出 #1

3
1
3

说明/提示

输入输出样例 1 解释

如下图,标记出了所有人感染瘟疫的时间以及感染源和领主的位置。

img

数据规模与约定

对于 100% 的数据,保证 1 ≤ n , m ≤ 500,1 ≤ a , b ≤ 105。

code1

#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

typedef pair<int,int> PII;
const int inf = 1e9;
const int N = 1e3+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};


int vis[N][N];
int g[N][N];
int n, m, a, b;
int flag = 1;

void bfs(int sx, int sy){
    queue<PII> que;
    que.push({sx,sy});
    vis[sx][sy] = 1;
    int count = 0;
    while(!que.empty() && count < 19000){
        count++;
        int x = que.front().first, y = que.front().second;
        que.pop();

        for(int i = 0; i < 4; i++){
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 1 || nx > n || ny < 1 || ny > n || vis[nx][ny] == flag) continue;
            vis[nx][ny] = flag;
            que.push({nx,ny});
            g[nx][ny] = min(g[nx][ny], g[x][y] + 1);
        }
    }
}

int main(){
    cin >> n >> m >> a >> b;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            g[i][j] = inf;
        }
    }

    int tx, ty;
    for(int i = 0; i < a; i++){
        cin >> tx >> ty;
        g[tx][ty] = 0;
        bfs(tx, ty);
        flag++;//标记此次是否被搜索过
    }

    for(int i = 0; i < b; i++){
        cin >> tx >> ty;
        cout << g[tx][ty] << endl;
    }
    return 0;
}

code2:

#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>

#define debug cout << "___debug___\n"; 
using namespace std;

typedef pair<int,int> PII;
const int inf = 1e9;
const int N = 1e3+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};

struct Node {
    int x, y, step;
    Node(int x, int y, int step){
        this->x = x;
        this->y = y;
        this->step = step;
    }
};

int vis[N][N];
int g[N][N];
int n, m, a, b;
int flag = 1;
queue<Node> que;

void init(){
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            g[i][j] = inf;
        }
    }
}

void bfs(){
    while(!que.empty()){
        int x = que.front().x, y = que.front().y, step = que.front().step;
        que.pop();
        g[x][y] = min(g[x][y], step);
        for(int i = 0; i < 4; i++){
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny]) continue;
            vis[nx][ny] = 1;
            que.push(Node(nx, ny, step + 1)); 
        }
    }
}

int main(){
    cin >> n >> m >> a >> b;
    init();
    int tx, ty;
    for(int i = 0; i < a; i++){
        cin >> tx >> ty;
        que.push(Node(tx,ty,0));
        g[tx][ty] = 0;
        vis[tx][ty] = 1;
    }
    bfs();
    for(int i = 0; i < b; i++){
        cin >> tx >> ty;
        cout << g[tx][ty] << endl;
    }
    return 0;
}

六、求细胞数量

题目链接:P1451 求细胞数量 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

一矩形阵列由数字 0 到 9 组成,数字 1到 9代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。

输入格式

第一行两个整数代表矩阵大小 n 和 m。

接下来 n 行,每行一个长度为 m 的只含字符 09 的字符串,代表这个 n×m 的矩阵。

输出格式

一行一个整数代表细胞个数。

输入输出样例

输入 #1

4 10
0234500067
1034560500
2045600671
0000000089

输出 #1

4

说明/提示

数据规模与约定

对于 100% 的数据,保证 1 ≤ n , m ≤ 100。

#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>

#define debug cout << "___debug___\n"; 
using namespace std;

typedef pair<int,int> PII;
const int inf = 1e9;
const int N = 1e2+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};

int vis[N][N];
char g[N][N];
int n, m, ans;
queue<PII> que;

void bfs(int sx, int sy){
    ans ++;
    que.push({sx,sy}); 
    vis[sx][sy] = 1;
    while(!que.empty()){
        int x = que.front().first, y = que.front().second;
        que.pop();
        for(int i = 0; i < 4; i++){
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny] || g[nx][ny] == '0') continue;
            vis[nx][ny] = 1;
            que.push({nx, ny}); 
        }
    }
}

int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            cin >> g[i][j];
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if(g[i][j] != '0' && !vis[i][j]) bfs(i, j);//记得判断该细胞是否被访问过,否则会重复很多
        }
    }
    cout << ans << endl;
    return 0;
}
举报

相关推荐

0 条评论