【vjudge训练记录】大一寒假专项训练——BFS

训练情况

A题

BFS模板题,BFS需要开一个队列记录当前搜索到的坐标,每次从队头取出来一个往其他方向遍历,记得判断移动后的位置是否合法,马显然可以往八个方向走,我们先初始化步数为 -1,然后起点位置步数为 \(0\),每次移动时步数等于原来的地方步数 +1,直接记录步数即可

点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
#define pii pair<int,int>

using namespace std;

const int N = 403;

int n,m,x,y;
bool v[N][N];
int u[8][2] = {{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};
int ans[N][N];

bool pd(int x,int y){
    return x>=1&&y>=1&&x<=n&&y<=m&&v[x][y]==0;
}

void bfs(int stx,int sty){
    ans[stx][sty] = 0;
    queue<pii> q;
    q.push({stx,sty});
    while(q.size()){
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        if(v[x][y]) continue;
        v[x][y] = 1;
        for(int i = 0;i<8;i++){
            int xx = x + u[i][0];
            int yy = y + u[i][1];
            if(!pd(xx,yy)) continue;
            ans[xx][yy] = ans[x][y] + 1;
            q.push({xx,yy});
        }
    }
}

void solve(){
    cin>>n>>m>>x>>y;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            ans[i][j] = -1;
        }
    }
    bfs(x,y);
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            cout<<ans[i][j]<<" ";
        }
        cout<<endl;
    }
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}

B题

这题还可以用并查集做,维护连通性再统计个数。BFS做法是遇到细胞就答案+1然后搜索,把相邻的细胞全部标记掉,如果遇到同一个细胞由于有标记就不会重复搜索

点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
#define pii pair<int,int>

using namespace std;

const int N = 403;

int n,m,x,y;
string s[N];
bool v[N][N];
int u[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
int ans;

bool pd(int x,int y){
    return x>=0&&y>=0&&x<n&&y<m&&v[x][y]==0&&s[x][y]!='0';
}

void bfs(int stx,int sty){
    queue<pii> q;
    q.push({stx,sty});
    while(q.size()){
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        if(v[x][y]) continue;
        v[x][y] = 1;
        for(int i = 0;i<4;i++){
            int xx = x + u[i][0];
            int yy = y + u[i][1];
            if(!pd(xx,yy)) continue;
            q.push({xx,yy});
        }
    }
}

void solve(){
    cin>>n>>m;
    for(int i = 0;i<n;i++) cin>>s[i];
    for(int i = 0;i<n;i++){
        for(int j = 0;j<m;j++){
            if(s[i][j] != '0' && !v[i][j]){
                ans++;
                bfs(i,j);
            }
        }
    }
    cout<<ans<<endl;
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}

C题

洪水是从边缘过来的,所以我们对矩阵的四条边进行BFS搜索,把相邻的 0 全部标记掉,遇到围墙过不去,最后全部遍历一遍,判断 0 的位置没有标记过就是洪水到不了的地方

点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
#define pii pair<int,int>

using namespace std;

const int N = 403;

int n,m,x,y;
string s[N];
bool v[N][N];
int u[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
int ans;

bool pd(int x,int y){
    return x>=0&&y>=0&&x<n&&y<m&&v[x][y]==0&&s[x][y]=='0';
}

void bfs(int stx,int sty){
    queue<pii> q;
    q.push({stx,sty});
    while(q.size()){
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        if(v[x][y]) continue;
        v[x][y] = 1;
        for(int i = 0;i<4;i++){
            int xx = x + u[i][0];
            int yy = y + u[i][1];
            if(!pd(xx,yy)) continue;
            q.push({xx,yy});
        }
    }
}

void solve(){
    cin>>n>>m;
    for(int i = 0;i<n;i++) cin>>s[i];
    for(int i = 0;i<n;i++){
        for(int j = 0;j<m;j++){
            if(i == 0 || i == n-1 || m == 0 || m == m-1){
                bfs(i,j);
            }
        }
    }
    for(int i = 0;i<n;i++){
        for(int j = 0;j<m;j++){
            if(s[i][j] == '0' && !v[i][j]) ans++;
        }
    }
    cout<<ans<<endl;
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}

D题

这题我们需要观察到一个性质,无论如何走,三棱锥翻过的位置朝下的数字都是固定的,所以我们可以先处理能到的地方(三棱锥朝下的数字和给定的数字一样),之后进行 BFS 搜索求最短路即可

这题由于初始三棱锥的情况固定,所以我们通过手玩发现,对于奇数行朝下的数字一定是 4 3 2 1 4 3 2 1 这样的循环,对于偶数行朝下的数字一定是 1 2 3 4 1 2 3 4 这样的循环,我们预处理能到的地方,显然左右两侧都可以随便翻,由于三角形有尖头朝上和尖头朝下两种情况,所以对于奇数列可以往下走,偶数列可以往上走,BFS的方向数组在移动的时候需要注意一下即可,初始化答案为最大值,一旦能走到终点就更新答案取小值

点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
#define pii pair<int,int>

using namespace std;

const int N = 300;

int n;
int a[N][N],b[N][N],step[N][N];
bool v[N][N];
bool vis[N][N];
int edx,edy;

int u[4][2] = {{0,-1},{0,1},{1,1},{-1,-1}};

int ans = INT_MAX;

bool pd(int x,int y){
    return x>=1&&x<=n&&y>=1&&y<=(2*x-1);
}

void bfs(int stx,int sty){
    queue<pii> q;
    q.push({stx,sty});
    while(q.size()){
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        if(x == edx && y == edy){
            ans = min(ans,step[x][y]);
        }
        if(vis[x][y] || !v[x][y]) continue;
        vis[x][y] = 1;
        for(int i = 0;i<4;i++){
            if(y%2==0 && i==2) continue;
            if(y%2==1 && i==3) continue;
            int xx = x + u[i][0];
            int yy = y + u[i][1];
            if(!pd(xx,yy) || !v[xx][yy]) continue;
            step[xx][yy] = step[x][y] + 1;
            q.push({xx,yy});
        }
    }
}

void solve(){
    cin>>n;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=2*i-1;j++){
            cin>>a[i][j];
        }
    }
    cin>>edx>>edy;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=2*i-1;j++){
            if(i&1){
                int x = j-1; x%=4;
                b[i][j] = 4-x;
            } else {
                int x = j-1; x%=4;
                b[i][j] = x+1;
            }
        }
    }
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=2*i-1;j++){
            if(a[i][j] == b[i][j]) v[i][j] = 1;
        }
    }
    // for(int i = 1;i<=n;i++){
    //     for(int j = 1;j<=2*i-1;j++){
    //         cout<<v[i][j]<<" ";
    //     }
    //     cout<<endl;
    // }
    bfs(1,1);
    if(ans == INT_MAX) cout<<-1<<endl;
    else cout<<ans<<endl;
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}
posted @ 2025-02-13 18:04  MNNUACM_2024ZY  阅读(136)  评论(0)    收藏  举报