广搜提高①
_yang_yi_bo_ · · 算法·理论
P1746 离开中山路
广搜的模板题,直接套板子就行了。
#include<bits/stdc++.h>
using namespace std;
int n;
char c[1005][1005];
bool vis[1005][1005];
int sx,sy,ex,ey;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
struct kkk{
int x,y,s;
};
int bfs(int sx,int sy,int ex,int ey){
queue<kkk> q;
q.push({sx,sy,0});
vis[sx][sy]=1;
while(!q.empty()){
kkk u=q.front();
q.pop();
for(int i=0;i<4;i++){
int xx=u.x+dx[i],yy=u.y+dy[i],ss=u.s+1;
if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&!vis[xx][yy]){
vis[xx][yy]=1;
q.push({xx,yy,ss});
if(xx==ex&&yy==ey){
return ss;
}
}
}
}return -1;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>c[i][j];
if(c[i][j]=='1'){
vis[i][j]=1;
}
}
}cin>>sx>>sy>>ex>>ey;
cout<<bfs(sx,sy,ex,ey);
return 0;
}
P6207 [USACO06OCT] Cows on Skates G
这一题是输出路径的问题,我们可以用一个
在走到终点后,我们可以递归输出路径,由于
#include<bits/stdc++.h>
using namespace std;
int n,m;
char c[155][155];
bool vis[155][155];
int sx,sy,ex,ey;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
struct kkk{
int x,y;
};
kkk pre[155][155];
void print(int x,int y){
if(x==114514&&y==114514){
return;
}print(pre[x][y].x,pre[x][y].y);
cout<<x<<" "<<y<<"\n";
}
void bfs(int sx,int sy,int ex,int ey){
queue<kkk> q;
q.push({sx,sy});
vis[sx][sy]=1;
pre[sx][sy].x=114514;
pre[sx][sy].y=114514;
while(!q.empty()){
kkk u=q.front();
q.pop();
for(int i=0;i<4;i++){
int xx=u.x+dx[i],yy=u.y+dy[i];
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&!vis[xx][yy]){
vis[xx][yy]=1;
q.push({xx,yy});
pre[xx][yy].x=u.x;
pre[xx][yy].y=u.y;
if(xx==ex&&yy==ey){
print(ex,ey);
return;
}
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c[i][j];
if(c[i][j]=='*'){
vis[i][j]=1;
}
}
}
bfs(1,1,n,m);
return 0;
}
P10234 [yLCPC2024] B. 找机厅
这题依然是用一个 题解上一题的代码复制过来,进行一点小小的改变。
首先,不仅要判断有没有访问过,还有判断上一个格子与现在所在的格子是否不相同。
最后,输出步数后,递归函数里要根据上一个点与现在的点判断上次往哪个方向走。
#include<bits/stdc++.h>
using namespace std;
int n,m;
char c[2005][2005];
bool vis[2005][2005];
int sx,sy,ex,ey;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int t;
struct kkk{
int x,y,s;
};
kkk pre[2005][2005];
void print(int x,int y){
if(x==114514&&y==114514){
return;
}print(pre[x][y].x,pre[x][y].y);
if(pre[x][y].x==x&&pre[x][y].y==y+1){
cout<<"L";
}else if(pre[x][y].x==x&&pre[x][y].y==y-1){
cout<<"R";
}else if(pre[x][y].x==x+1&&pre[x][y].y==y){
cout<<"U";
}else if(pre[x][y].x==x-1&&pre[x][y].y==y){
cout<<"D";
}
}
void bfs(int sx,int sy,int ex,int ey){
queue<kkk> q;
q.push({sx,sy,0});
vis[sx][sy]=1;
pre[sx][sy].x=114514;
pre[sx][sy].y=114514;
while(!q.empty()){
kkk u=q.front();
q.pop();
for(int i=0;i<4;i++){
int xx=u.x+dx[i],yy=u.y+dy[i],ss=u.s+1;
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&!vis[xx][yy]&&(c[xx][yy]=='1'&&c[u.x][u.y]=='0'||c[xx][yy]=='0'&&c[u.x][u.y]=='1')){
vis[xx][yy]=1;
q.push({xx,yy,ss});
pre[xx][yy].x=u.x;
pre[xx][yy].y=u.y;
if(xx==ex&&yy==ey){
cout<<ss<<"\n";
print(ex,ey);
return;
}
}
}
}cout<<-1;
}
void work(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c[i][j];
vis[i][j]=0;
pre[i][j].x=0;
pre[i][j].y=0;
}
}bfs(1,1,n,m);
cout<<"\n";
}
int main(){
cin>>t;
while(t--){
work();
}
return 0;
}
P10487 Nightmare II
这题要用到双向广搜,使用两个队列,一个存储男生所在的点,一个存储女生所在的点,并使用两个标记数组,一个标记男生走过的点,一个标记女生走过的点。
对于鬼魂,由于鬼魂会穿墙,所以鬼魂走到一个点走的步数为两点之间的曼哈顿距离,时间为
注意
#include<bits/stdc++.h>
using namespace std;
char a[1005][1005];
int n,m,t;
struct kkk{
int x,y,f;
};
bool vis[1005][1005][2];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
vector<kkk> op;
int sumt=0;
int dis(kkk a,kkk b){
return abs(a.x-b.x)+abs(a.y-b.y);
}bool check1(int x,int y,int k){
if(a[x][y]!='X'&&x>=1&&x<=n&&y>=1&&y<=m&&vis[x][y][k]==0){
return true;
}return false;
}bool check2(kkk a){
for(int i=0;i<2;i++){
if(dis(a,op[i])<=2*sumt){
return false;
}
}return true;
}
queue<kkk> q1;
queue<kkk> q2;
int bfs(){
while(!q1.empty()&&!q2.empty()){
sumt++;
int tot=3;
while(tot--){
int len=q1.size();
while(len--){
kkk u=q1.front();
q1.pop();
if(!check2(kkk{u.x,u.y})){
continue;
}for(int i=0;i<4;i++){
int xx=u.x+dx[i];
int yy=u.y+dy[i];
if(check1(xx,yy,u.f)&&check2(kkk{xx,yy})){
vis[xx][yy][u.f]=1;
if(vis[xx][yy][!u.f]){
return sumt;
}q1.push(kkk{xx,yy,u.f});
}
}
}
}tot=1;
while(tot--){
int len=q2.size();
while(len--){
kkk u=q2.front();
q2.pop();
if(!check2(kkk{u.x,u.y})){
continue;
}for(int i=0;i<4;i++){
int xx=u.x+dx[i];
int yy=u.y+dy[i];
if(check1(xx,yy,u.f)&&check2(kkk{xx,yy})){
vis[xx][yy][u.f]=1;
if(vis[xx][yy][!u.f]){
return sumt;
}q2.push(kkk{xx,yy,u.f});
}
}
}
}
}return -1;
}
void init(){
memset(vis,0,sizeof vis);
while(!q1.empty()){
q1.pop();
}while(!q2.empty()){
q2.pop();
}op.clear();
sumt=0;
}
int main(){
cin>>t;
while(t--){
init();
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
if(a[i][j]=='M'){
q1.push({i,j,0});
vis[i][j][0]=1;
}else if(a[i][j]=='G'){
q2.push({i,j,1});
vis[i][j][1]=1;
}else if(a[i][j]=='Z'){
op.push_back(kkk{i,j});
}
}
}cout<<bfs()<<"\n";
}
return 0;
}
P2199 最后的迷宫
这一题同样是多组数据,要注意清空。
有两个坑点:
-
注意刚开始就能看到奖杯时,要直接输出
0 ; -
注意起点与终点是反着输入的。
接着我们说一下思路。
由于这题
展示一下如何初始化二维动态数组:
a.resize(n);
for(int i=0;i<n;i++){
a[i].resize(m);
}
如果习惯从一开始的话,可以将空间定义大一点。
另外,我们还可以使用一个 bool 数组来记录哈利能看到奖杯的地方,将有奖杯的地方向八个方向遍历即可。
#include<bits/stdc++.h>
using namespace std;
vector<vector<char> > a;
int n,m;
int sx,sy,ex,ey;
vector<vector<bool> > finish,vis;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int fx[8]={1,0,-1,0,1,1,-1,-1};
int fy[8]={0,1,0,-1,1,-1,1,-1};
struct kkk{
int x,y,step;
};
void init(int ex,int ey){
for(int i=0;i<8;i++){
int x=ex,y=ey;
while(true){
if(x<1||y<1||x>n||y>m||a[x][y]=='X'){
break;
}finish[x][y]=1;
x+=fx[i];
y+=fy[i];
}
}
}
void bfs(int sx,int sy,int ex,int ey){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
finish[i][j]=0;
vis[i][j]=0;
}
}init(ex,ey);
queue<kkk> q;
q.push({sx,sy,0});
vis[sx][sy]=1;
if(finish[sx][sy]==1){
cout<<0<<"\n";
return ;
}
while(!q.empty()){
kkk u=q.front();
q.pop();
for(int i=0;i<4;i++){
int xx=u.x+dx[i],yy=u.y+dy[i],ss=u.step+1;
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&!vis[xx][yy]&&a[xx][yy]=='O'){
q.push({xx,yy,ss});
vis[xx][yy]=1;
if(finish[xx][yy]==1){
cout<<ss<<"\n";
return;
}
}
}
}cout<<"Poor Harry\n";
}
int main(){
cin>>n>>m;
a.resize(n+5);
finish.resize(n+5);
vis.resize(n+5);
for(int i=1;i<=n+3;i++){
a[i].resize(m+5);
finish[i].resize(m+5);
vis[i].resize(m+5);
}for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}while(true){
cin>>ex>>ey>>sx>>sy;
if(sx==0&&sy==0&&ex==0&&ey==0){
return 0;
}bfs(sx,sy,ex,ey);
}
return 0;
}