您的位置:首页 > 其它

BFS(9)

2020-02-02 19:45 246 查看

BFS(这篇东西主要靠大家慢慢理解感受)

前面陆陆续续的讲的都是一些很基础很容易的算法,这篇讲的东西真的是有点难了,并不是板子的问题,而是因为他太抽象了,全靠读者自己想象力。可能是小编的水平不够,真的是有种只可意会不可言传的感觉,不过小编还是尽力为大家讲清楚这个BFS。注:有一些基础的东西读者直接百度吧,没必要讲。
再补充一点,BFS和DFS就是遍历图的俩种方法,他的目的很明确,就是在图中找一些东西。

传送门: Red and Black HDU - 1312

小编在这用一种别的思路:先把所有位置都放成#,然后遇见#不能走,走过的点变成#。另外的一种方法就是再开一个二维数组,把走过的点记成1,没走的记成0(后面会用到,简单,到时候读者再理解)
也没有一个确切的板子,直接看下面的这个板子题吧

//#include <bits/stdc++.h>
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
typedef long long ll;
int x,y,x1,y11;
char c[30][30];
int dx[4]={-1,0,0,1};
int dy[4]={0,-1,1,0}; //坐标系下的四个方向
//可以写成dd[4][2]={-1,0,1,0,0,-1,0,1} ,一个意思
struct node
{
int x,y;
}now,nt;  //不要问为什么不用 next,因为next是一个已经有的函数
//now表示当前所在位置,nt表示下步可以走到的位置
int main()
{
while(~scanf("%d %d",&x,&y)&&x&&y)
{
int sum=1;
memset(c,'#',sizeof(c));  //将整个图先初始化为“#”;

for(int i=1;i<=y;i++)    //存图,用cin,不用这么麻烦
{						 //用scanf这样存,注意 getchar();
getchar();
for(int j=1;j<=x;j++)
{
scanf("%c",&c[i][j]);
if(c[i][j]=='@')
{
x1=i;
y11=j;  //找见入口 入口标记下来
}
}
}

queue<node> q;
now.x=x1;
now.y=y11;
q.push(now);        //把现在所在位置压入队列
c[x1][y11]='#';     //走过的路变成#
while(!q.empty())
{
now=q.front();        //从这个点开始走
for(int i=0;i<4;i++)  //四个方向
{
nt.x=now.x+dx[i];
nt.y=now.y+dy[i];   //表示向哪个方向走
if(c[nt.x][nt.y]!='#') //如果下个坐标没走过,就进去
{
sum++;
c[nt.x][nt.y]='#';  //走过的点变成#
q.push(nt);        //把能到达的坐标都压入队列里面
}
}
q.pop();               // 当前的这个坐标从队列中弹出去
}
printf("%d\n",sum);
}
return 0;
}

传送门:Rescue HDU - 1242

换种写法,不过思路一样。这种写法更为常见,但是有点麻烦。(具体的代码自己看吧,和上题基本一样,就是表达方式不同)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,x,y,x_1,x2,y_1,y2;;         //该死的编译器定义不了y1。。。
char a[205][205];                    //存图
int b[205][205];                     //用来记录是否走过,走过就赋值为1 ,否则就是0
int d[4][2]={-1,0,1,0,0,1,0,-1};     //注意这种表达方式。
struct node
{
int x,y,step;
friend bool operator < (node a,node b)
{
return a.step>b.step;
}
}now,nt;
int BFS()
{
priority_queue <node> q;
now.x=x2; now.y=y2; now.step=0;
q.push(now);
while(!q.empty())
{
now=q.top();
q.pop();
x=now.x; y=now.y;
if(x==x_1&&y==y_1)
return now.step;
b[x][y]=1;
for(int i=0;i<4;i++)
{
x=now.x+d[i][0];
y=now.y+d[i][1];
if(x>0&&y>0&&x<=n&&y<=m&&b[x][y]==0&&a[x][y]!='#')
{
nt.x=x; nt.y=y; nt.step=now.step+1;
if(a[x][y]=='x')
nt.step++;
q.push(nt);
}
}
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m)  //行列
{
int s=0;
memset(b,0,sizeof b);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
if(a[i][j]=='a')
{
x_1=i;
y_1=j;
}
if(a[i][j]=='r')
{
x2=i;
y2=j;
b[i][j]=1;
}
}
}
s=BFS();
if(s)
cout<<s<<endl;
else
cout<<"Poor ANGEL has to stay in the prison all his life."<<endl;
}
return 0;
}

看了俩个平面的,看一个立体的逃生题

传送门: Dungeon Master POJ - 2251

(思路还是一模一样,大家自己看吧)

#include<iostream>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
char c[50][50][50];
int l,m,n,x1,y1,z1;
int dd[6][3]={{-1,0,0},{0,-1,0},{0,0,-1},{1,0,0},{0,1,0},{0,0,1}};
struct node
{
int x;
int y;
int z;
int time;
friend bool operator < (node a,node b)
{
return a.time >b.time;
}
}now,next;

int BFS()
{
int ans=0;
priority_queue<node> q;
now.x=x1;
now.y=y1;
now.z=z1;
now.time=0;
q.push(now);
c[x1][y1][z1]='#';
while(!q.empty())
{
now=q.top();
for(int i=0;i<6;i++)
{
next.x=now.x+dd[i][0];
next.y=now.y+dd[i][1];
next.z=now.z+dd[i][2];
next.time=now.time+1;
if(c[next.x][next.y][next.z]!='#')
{
if(c[next.x][next.y][next.z]=='E')
{
//next.time++;
ans=next.time;
break;
}
c[next.x][next.y][next.z]='#';
q.push(next);
}
}
q.pop();
}
return ans;
}

int main()
{
while(~scanf("%d%d%d",&l,&m,&n)&&l&&m&&n)
{
memset(c,'#',sizeof(c));
for(int i=1;i<=l;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=1;k<=n;k++)
{
cin>>c[i][j][k];
if(c[i][j][k]=='S')
{
x1=i;
y1=j;
z1=k;
}
}

}
}

int ss=BFS();
if(ss)
printf("Escaped in %d minute(s).\n",ss);
else
printf("Trapped!\n");
}
return 0;
}

传送门:Catch That Cow POJ - 3278

(一模一样的题,提供一个代码)

//#include <bits/stdc++.h>
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
typedef long long ll;
struct node
{
int x,step;
}a,next;

int main()
{
int n,k;
while(~scanf("%d %d",&n,&k))
{
int ans=0;
int vis[100010];
queue<node> q;
memset(vis,0,sizeof(vis));
a.x=n;
a.step=0;
vis[n]=1;
q.push(a);
while(!q.empty())
{
a=q.front();
if(a.x==k)
{
ans=a.step;
break;
}
else
{
if(a.x*2<=100000&&!vis[a.x*2])
{
vis[a.x*2]=1;
next.x=a.x*2;
next.step=a.step+1;
q.push(next);
}
if(a.x+1<=100000&&!vis[a.x+1])
{
vis[a.x+1]=1;
next.x=a.x+1;
next.step=a.step+1;
q.push(next);
}
if(a.x-1<=100000&&!vis[a.x-1])
{
vis[a.x-1]=1;
next.x=a.x-1;
next.step=a.step+1;
q.push(next);
}
q.pop();
}
}
printf("%d\n",ans);
}
return 0;
}

传送门:Battle City POJ - 2312

(都是一模一样的代码,建议做做,就当练手)

#include<iostream>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=305;
int n, m, sx, sy, ex, ey;
char mp[maxn][maxn];
bool vis[maxn][maxn];
int dir[4][2]={{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

struct node{
int x, y, steps;
bool operator < (const node &tmp) const {
return steps>tmp.steps;
}
};

int BFS(){
memset(vis, false, sizeof(vis));
priority_queue<node> q;
q.push((node){sx, sy, 0});
vis[sx][sy]=true;
while(q.size())
{
node tmp;
tmp=q.top();
q.pop();
if(tmp.x==ex && tmp.y==ey)
{
return tmp.steps;
}
for(int i=0; i<4; i++)
{
int tx=tmp.x+dir[i][0];
int ty=tmp.y+dir[i][1];
if(tx<0 || tx>=n || ty<0 || ty>=m)
continue;
if((mp[tx][ty]=='E'||mp[tx][ty]=='T') && vis[tx][ty]==false)
{
q.push((node){tx, ty, tmp.steps+1});
vis[tx][ty]=true;
}
else if(mp[tx][ty]=='B' && vis[tx][ty]==false)
{
q.push((node){tx, ty, tmp.steps+2});
vis[tx][ty]=true;
}
}
}
return -1;
}

int main(){
while(~scanf("%d%d", &n, &m) && (n||m))
{
for(int i=0; i<n; i++)
{
scanf("%s", mp+i);
for(int j=0; j<m; j++)
{
if(mp[i][j]=='Y')
{
sx=i; sy=j;
}
else if(mp[i][j]=='T')
{
ex=i; ey=j;
}
}
}
printf("%d\n", BFS());

}
return 0;
}

传送门:Knight Moves HDU - 1372

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dd[8][2]= {{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2}};
int x_1,y_1,x2,y2;
int c[100][100];  //用来标记走过的点
struct node
{
int x,y,step;
friend bool operator < (node a,node b)
{
return a.step>b.step;
}
}now,nt;
int BFS()
{
memset(c,0,sizeof c);
c[x_1][y_1]=1;
priority_queue<node> q;
now.x=x_1; now.y=y_1; now.step=0;
q.push(now);
while(!q.empty())
{
now=q.top();
if(now.x==x2&&now.y==y2)
return now.step;

for(int i=0;i<8;i++)
{
nt.x=now.x+dd[i][0];
nt.y=now.y+dd[i][1];
if(nt.x>0&&nt.x<=8&&nt.y>0&&nt.y<=8&&c[nt.x][nt.y]==0)
{
nt.step=now.step+1;
q.push(nt);
c[nt.x][nt.y]=1;
}
}
q.pop();
}
return 0;
}
int main()
{
char a[3],b[3];
while(~scanf("%s %s",&a,&b))
{
x_1=a[0]-'a'+1;
y_1=a[1]-'0';
x2=b[0]-'a'+1;
y2=b[1]-'0';
printf("To get from %s to %s takes %d knight moves.\n",a,b,BFS());
}
return 0;
}

传送门:Robot Motion POJ - 1573 (特有意思,涉及新方法)

很有意思的一个题,做了半天没做出来,最后百度了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[12][12];
int vis[12][12];
int main()
{
int a,b,c;
while(scanf("%d %d %d",&a,&b,&c))
{
memset(vis,0,sizeof(vis));
if(a==0&&b==0&&c==0)
break;
for(int i=0;i<a;i++)
for(int j=0;j<b;j++)
cin>>s[i][j];
int x=0,y=c-1,step=0;

while(true)
{
step++;
if(s[x][y]=='N'&&!vis[x][y])
{
vis[x][y]=step;
x--;
}
else if(s[x][y]=='S'&&!vis[x][y])
{
vis[x][y]=step;
x++;
}
else if(s[x][y]=='W'&&!vis[x][y])
{
vis[x][y]=step;
y--;
}
else if(s[x][y]=='E'&&!vis[x][y])
{
vis[x][y]=step;
y++;
}

if(x<0||x==a||y<0||y==b)
{
printf("%d step(s) to exit\n",step);
break;
}
else if(vis[x][y])
{
printf("%d step(s) before a loop of %d step(s)\n",vis[x][y]-1,step+1-vis[x][y]);
break;
}
}
}
}

传送门: Number Transformation LightOJ - 1141

我的天,差点没看懂题。给你一个整数A和B,A可以加上自己本身的质因数(不包括1和本身)【这点很重要】,从而等于B,问A通过加的操作的最少次数。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 2005;
int p[2005];
int vis[2005];
void init()
{
p[1]=p[0]=1;
for(int i=2;i<sqrt(maxn);i++)
{
for(int j=i*2;j<maxn;j+=i)
p[j]=1;
}
}
struct node{
int x,step;
};
int flag;
void bfs(int x,int y)
{
memset(vis,0,sizeof(vis));
flag=-1;
queue<node> q;
node now,mid;
now.x=x;now.step=0;
vis[x]=1;
q.push(now);
int ans=-1;
while(!q.empty())
{
now=q.front();
q.pop();
for(int i=2;i<now.x;i++)
{
if(now.x%i==0&&!p[i])
{
mid.x=now.x+i;
if(vis[mid.x]||mid.x>y)    continue;
vis[mid.x]=1;
mid.step=now.step+1;
if(mid.x==y)
{
flag=mid.step;
return ;
}
q.push(mid);
}
}
}
}
int main()
{
int n,a,b;
cin>>n;
init();
int cnt=1;
while(n--)
{
int a,b;
cin>>a>>b;
cout<<"Case "<<cnt++<<": ";
if(a==b)
{
puts("0");
continue;
}
bfs(a,b);
cout<<flag<<endl;
}
}
  • 点赞
  • 收藏
  • 分享
  • 文章举报
〆℡小短腿走快点ゝ 发布了30 篇原创文章 · 获赞 1 · 访问量 1419 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: