训练情况
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;
}