********广度优先搜索*********

目录

 

BFS算法:

广度优先搜索算法

POJ 3278 Catch That Cow

百练 4116:拯救行动



BFS算法:

思路:

1.从初始状态S开始,利用规则,生成下一层的状态。

2.顺序检查下一层的所有状态,看是否出现目标状态G。

否则就对该层所有状态节点,分别利用规则。生成再下一层的所有状态节点。

3.继续按照上面思想生成下一层的所有状态节点,这样一层一层往下展开。

直到出现目标状态为止

先遍历离起点近的,再到远的,网上有一个很形象的例子:你的眼镜掉在地上以后,你趴在地板上找。你总是先摸离你最近的地方,如果没有,再摸距离较远的地方。

通常用队列来实现

初始化队列Q

Q={起点s};

标记s为已访问;

while(Q非空)

{

   取Q队首元素u;

   u出队;

if(u==目标状态)

{.............}

所有与u相邻且未被访问的点进入队列;

标记u为已访问;

}

广度优先搜索算法如下:(用 QUEUE )
(1) 把初始节点 S0 放入 Open 表中;
(2) 如果 Open 表为空,则问题无解失败 退出;
(3) 把Open 表的第一个节点取出放入 Closed 表,并记该节点为 n;
(4) 考察节点 n是否为目标节点。若, 则得到问题的解,成功退出;
(5) 若节点 n不可扩展,则转第 (2) 步;
(6) 扩展节点 n,将其不在 Closed 表和 Open 表中的子节点 (判重) 放入 Open 表的尾部 ,并为每一个子节点设置指向父的针 (或记录节点的层次) ,然后转第 (2) 步

这个网址有BFS例子具体的实现过程:

BFS的具体实现过程

POJ 3278 Catch That Cow

Description

Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.

* Walking: FJ can move from any point X to the points - 1 or + 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.

If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?

Input

Line 1: Two space-separated integers: N and K

Output

Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.

Sample Input

5 17

Sample Output

4

Hint

The fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.

Source

USACO 2007 Open Silver

北大课件代码:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn=1e5;
int n,k;
int vis[maxn+10];
struct step
{
	int x;
	int steps;
    step(int xx,int s):x(xx),steps(s){ }
};
queue<step>Q;
void bfs()
{
	 while(!Q.empty())
	{
		step s=Q.front();
		if(s.x==k)
		{
			cout<<s.steps<<endl;
			return ;
		}
		else
		{
			if(s.x-1>=0 && !vis[s.x-1])
			{
				Q.push(step(s.x-1,s.steps+1));
				vis[s.x-1]=1;
			}
			if(s.x+1<=maxn && !vis[s.x+1])//步数小于maxn
			{
				Q.push(step(s.x+1,s.steps+1));
				vis[s.x+1]=1;
			}
			if(s.x*2<=maxn && !vis[s.x*2])//步数小于maxn
			{
				Q.push(step(s.x*2,s.steps+1));
				vis[s.x*2]=1;
			}
			Q.pop();
		}
	}
	return ;
}
int main()
{
	cin>>n>>k;
	memset(vis,0,sizeof(vis));
    Q.push(step(n,0));
    vis[n]=1;
    bfs();
    return 0;
}

 注意:

1.s.x+1<=maxn,s.x*2<=maxn。

自己之前代码:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn=200100;//注意这个地方的取值,maxn=1e5+100 POJ上交 Runtime Error
struct Node
{
int x;
int step;	
};
int n,k;
int vis[maxn];
queue<Node>Q;
void bfs()
{
	
	while(!Q.empty())
	{
		Node w2=Q.front();
		Q.pop();
		int x=w2.x;
		int step=w2.step;
		if(x==k)
		{
			cout<<step<<endl;
			return ;
		}
		if(x<=k && !vis[x+1])
		{
			Node w3;
			vis[x+1]=1;
			w3.x=x+1;
			w3.step=step+1;
			Q.push(w3);
		}
		if(x>=1 && !vis[x-1])
		{
			Node w3;
			vis[x-1]=1;
			w3.x=x-1;
			w3.step=step+1;
			Q.push(w3);
		}
		if(x<=k && !vis[2*x])
		{
			Node w3;
			vis[2*x]=1;
			w3.x=x*2;
			w3.step=step+1;
			Q.push(w3);
		}
	}
}
int main()
{
	while(scanf("%d%d",&n,&k)!=EOF)
	{
		while(!Q.empty())
		 Q.pop();
		memset(vis,0,sizeof(vis));
		vis[n]=1;
		Node w1;
        w1.x=n;
        w1.step=0;
		Q.push(w1);
		bfs();
	}
	return 0;
}

百练 4116:拯救行动

描述

公主被恶人抓走,被关押在牢房的某个地方。牢房用N*M (N, M <= 200)的矩阵来表示。矩阵中的每项可以代表道路(@)、墙壁(#)、和守卫(x)。 
英勇的骑士(r)决定孤身一人去拯救公主(a)。我们假设拯救成功的表示是“骑士到达了公主所在的位置”。由于在通往公主所在位置的道路中可能遇到守卫,骑士一旦遇到守卫,必须杀死守卫才能继续前进。 
现假设骑士可以向上、下、左、右四个方向移动,每移动一个位置需要1个单位时间,杀死一个守卫需要花费额外的1个单位时间。同时假设骑士足够强壮,有能力杀死所有的守卫。

给定牢房矩阵,公主、骑士和守卫在矩阵中的位置,请你计算拯救行动成功需要花费最短时间。

输入

第一行为一个整数S,表示输入的数据的组数(多组输入)
随后有S组数据,每组数据按如下格式输入 
1、两个整数代表N和M, (N, M <= 200). 
2、随后N行,每行有M个字符。"@"代表道路,"a"代表公主,"r"代表骑士,"x"代表守卫, "#"代表墙壁。

输出

如果拯救行动成功,输出一个整数,表示行动的最短时间。
如果不可能成功,输出"Impossible"

样例输入

2
7 8
#@#####@
#@a#@@r@
#@@#x@@@
@@#@@#@#
#@@@##@@
@#@@@@@@
@@@@@@@@ 
13 40
@x@@##x@#x@x#xxxx##@#x@x@@#x#@#x#@@x@#@x
xx###x@x#@@##xx@@@#@x@@#x@xxx@@#x@#x@@x@
#@x#@x#x#@@##@@x#@xx#xxx@@x##@@@#@x@@x@x
@##x@@@x#xx#@@#xxxx#@@x@x@#@x@@@x@#@#x@#
@#xxxxx##@@x##x@xxx@@#x@x####@@@x#x##@#@
#xxx#@#x##xxxx@@#xx@@@x@xxx#@#xxx@x#####
#x@xxxx#@x@@@@##@x#xx#xxx@#xx#@#####x#@x
xx##@#@x##x##x#@x#@a#xx@##@#@##xx@#@@x@x
x#x#@x@#x#@##@xrx@x#xxxx@##x##xx#@#x@xx@
#x@@#@###x##x@x#@@#@@x@x@@xx@@@@##@@x@@x
x#xx@x###@xxx#@#x#@@###@#@##@x#@x@#@@#@@
#@#x@x#x#x###@x@@xxx####x@x##@x####xx#@x
#x#@x#x######@@#x@#xxxx#xx@@@#xx#x#####@

样例输出

13
7

一开始做这个题目的时候,觉得像 Catch That Cow,只不过多计算了步数而已,所以我就用了普通队列,按照上下左右四个方向走,是守卫步数就+2,是通道步数就+1,但是我忘记考虑了一个问题,在走有守卫和通道这两种选择上,应该选择步数最少了,所以应该用优先队列。.

 

自己代码: 

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn=250;
struct Node
{
	int x;
	int y;
	int step;
	bool operator<(const Node &n)const{
	   return step>n.step;
	}
};
char g[maxn][maxn];
int n,m;
int u,v;
int vis[maxn][maxn];
int dir[4][2]={1,0,0,1,-1,0,0,-1};
priority_queue<Node>Q;
void bfs()
{
	Node now,last;
	while(!Q.empty())
	{
		last=Q.top();
		Q.pop();
		int x=last.x;
		int y=last.y;
		int step=last.step;
	    for(int i=0;i<4;i++)
	    {
	        now.x=x+dir[i][0];
	        now.y=y+dir[i][1];
	     if(now.x>=0 && now.x<n && now.y>=0 && now.y<m && !vis[now.x][now.y] && g[now.x][now.y]!='#')
	     {
	     	if(g[now.x][now.y]=='x')
	     	{
	     	  	 Node w1;
				 w1.x=now.x;
				 w1.y=now.y;
				 w1.step=step+2;
				 vis[now.x][now.y]=1;
				 Q.push(w1);
			}
			if(g[now.x][now.y]=='@')
			{
				Node w1;
				w1.x=now.x;
				w1.y=now.y;
				w1.step=step+1;
				vis[now.x][now.y]=1;
				Q.push(w1);
			}
			if(g[now.x][now.y]=='a') //如果找到公主的位置,步数+1,然后输出即可
			{
				printf("%d\n",step+1);
		       return ;
			}
		 }
		}
	}
	cout<<"Impossible"<<endl;
}
int main()
{
	int S;
	while(scanf("%d",&S)!=EOF)
	{
		while(S--)
		{
			scanf("%d%d",&n,&m);
			memset(vis,0,sizeof(vis));
			while(!Q.empty())
				Q.pop();
			for(int i=0;i<n;i++)
			{
				scanf("%s",g[i]);
			}
			for(int i=0;i<n;i++)
			{
				for(int j=0;j<m;j++)
				{
					if(g[i][j]=='r')
					{
						Node t;
						t.x=i;
						t.y=j;
						t.step=0;
						vis[i][j]=1;
						Q.push(t);
					}
					if(g[i][j]=='a')
					{
						u=i;
						v=j;
					}
				}
			}
			bfs();
		}
	}
	return 0;
}

错误代码:没有把公主的坐标放进队列

void bfs()
{
	Node now,last;
	while(!Q.empty())
	{
		last=Q.top();
		Q.pop();
		int x=last.x;
		int y=last.y;
		int step=last.step;
		printf("x=%d y=%d\n",x,y);
		if(x==u && y==v)//公主坐标不在队列中,所以永远不会执行这一句if语句,也就不会输出步数
		{
		   printf("%d\n",step);
		   return ;	
	    }
	    for(int i=0;i<4;i++)
	    {
	        now.x=x+dir[i][0];
	        now.y=y+dir[i][1];
	     if(now.x>=0 && now.x<n && now.y>=0 && now.y<m && !vis[now.x][now.y] && g[now.x][now.y]!='#')
	     {
	     	if(g[now.x][now.y]=='x')
	     	{
	     	  	 Node w1;
				 w1.x=now.x;
				 w1.y=now.y;
				 w1.step=step+2;
				 vis[now.x][now.y]=1;
				 Q.push(w1);
			}
			if(g[now.x][now.y]=='@')
			{
				Node w1;
				w1.x=now.x;
				w1.y=now.y;
				w1.step=step+1;
				vis[now.x][now.y]=1;
				Q.push(w1);
			}
		 }
		}
	}
	cout<<"Impossible"<<endl;
}

 

注意:

1.一开始只判断了骑士走的是道路还是 守卫,并没有判断公主的位置,找到通道和守卫的位置,记录坐标和步数,放进队列,找到公主的位置也应该记录坐标的和步数,这样在另一层循环的时候取队头,取到公主的坐标,才能进入if语句输出步数。

 课件代码:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn=250;
struct Node
{
	int x;
	int y;
	int step;
	bool operator<(const Node &f)const{//重载的小于运算符 在push/top中用到了
	   return step>f.step;//最小值优先
	}
	Node(int xx,int yy,int ss):x(xx),y(yy),step(ss){ }//给x,y,step不算赋值
};
char g[maxn][maxn];
int n,m;
int u,v;
int vis[maxn][maxn];
int dir[4][2]={1,0,0,1,-1,0,0,-1};
priority_queue<Node>Q;
void bfs()
{
	while(!Q.empty())
	{
		int hx=Q.top().x;
		int hy=Q.top().y;
		int hs=Q.top().step;
		Q.pop();
		//vis[hx][hy]=1;
	//	printf("hx= %d hy=%d hs=%d\n",hx,hy,hs);
		if(hx==u && hy==v)
		{
			printf("%d\n",hs);
			return ;
		}
		for(int i=0;i<4;i++)
		{
			int nowx=hx+dir[i][0];
			int nowy=hy+dir[i][1];
			if(nowx>=0 && nowx<n && nowy>=0 && nowy<m && !vis[nowx][nowy] && g[nowx][nowy]!='#')
			{
				if(g[nowx][nowy]=='x')
				{
					Q.push(Node(nowx,nowy,hs+2));
				}
				else
				{
					Q.push(Node(nowx,nowy,hs+1));
				}
				vis[nowx][nowy]=1;
			}
		}
	}
	cout<<"Impossible"<<endl;
} 
int main()
{
	int S;
	while(scanf("%d",&S)!=EOF)
	{
		while(S--)
	    {
	    	memset(vis,0,sizeof(vis));
	    	while(!Q.empty())
	    	 Q.pop();
	    	scanf("%d%d",&n,&m);
	    	for(int i=0;i<n;i++)
	    	 scanf("%s",g[i]);
	    	for(int i=0;i<n;i++) 
	    	{
	    		for(int j=0;j<m;j++)
	    		{
	    			if(g[i][j]=='r')
	    			{
	    			  // printf("i=%d j=%d\n",i,j);
	    				vis[i][j]=1;
	    				Q.push(Node(i,j,0));
					}
					if(g[i][j]=='a')
					{
						//printf("u=%d v=%d\n",u,v);
						u=i;
						v=j;
					}
				}
			}
			bfs();
		}
	}
	return 0;
}

注意:

1.g[i][j]=='a', 两个等于号,不要漏掉。

2.使用优先队列。

4115:鸣人和佐助

描述

佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢?

已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有大蛇丸的手下,需要先打败大蛇丸的手下才能到这些位置。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,每移动一个距离需要花费1个单位时间,打败大蛇丸的手下不需要时间。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?

输入

输入的第一行包含三个整数:M,N,T。代表M行N列的地图和鸣人初始的查克拉数量T。0 < M,N < 200,0 ≤ T < 10
后面是M行N列的地图,其中@代表鸣人,+代表佐助。*代表通路,#代表大蛇丸的手下。

输出

输出包含一个整数R,代表鸣人追上佐助最少需要花费的时间。如果鸣人无法追上佐助,则输出-1。

样例输入

样例输入1
4 4 1
#@##
**##
###+
****

样例输入2
4 4 2
#@##
**##
###+
****

样例输出

样例输出1
6

样例输出2
4

多一个判断查克拉的数组,因此要多一步

 问题代码:   两种方式均没有记录查克拉。

/*
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn=250;
int n,m,t;
int u,v;
struct Node
{
	int x;
	int y;
	int minute;
	int ckl;
	Node(int xx,int yy,int mm,int cc): x(xx),y(yy),minute(mm),ckl(cc){ }
};
char g[maxn][maxn];
int vis[maxn][maxn];
int dir[4][2]={1,0,0,1,-1,0,0,-1};
queue<Node>Q;
void bfs()
{
	while(!Q.empty())
	{
		int hx=Q.front().x;
		int hy=Q.front().y;
		int hm=Q.front().minute;
		int hc=Q.front().ckl;
		if(hx==u && hy==v)
		{
			printf("%d\n",hm);
			return ;
		}
		for(int i=0;i<4;i++)
		{
			int nx=hx+dir[i][0];
			int ny=hy+dir[i][1];
			if(nx>=0 && nx<m&&ny>=0&& ny<n&&!vis[nx][ny])
			{
				if(g[nx][ny]=='*')
				{
				    Q.push(nx,ny,hm+1,hc);
				}
				if(g[nx][ny]=='#'&&hc>0)
				{
					Q.push(nx,ny,hm+1,hc-1);
				}
				if(g[nx][ny]=='+')
				{
					Q.push(nx,ny,hm+1,hc)
				}
			}
		}
	}
	puts("-1");
}
int main()
{
	scanf("%d%d%d",&m,&n,&t);
	memset(vis,0,sizeof(vis));
	while(!Q.empty())
         Q.pop();
	for(int i=0;i<m;i++)
	{
		scanf("%s",g[i]);
	}
    for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
	  {
		if(g[i][j]=='@')
	   {
	//	printf("i=%d j=%d\n",i,j);
          vis[i][j]=1;
           Q.push(Node(i,j,0,t));
	   }
		if(g[i][j]=='+')
	   {
			u=i;
			v=j;
	//	printf("u=%d v=%d\n",u,v);
    	}
	  }
	}
	bfs();		
	return 0;
}
*/


#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn=250;
int n,m,t;
int u,v;
struct Node
{
	int x;
	int y;
	int minute;
	int ckl;
};
char g[maxn][maxn];
int vis[maxn][maxn][maxn];
int dir[4][2]={1,0,0,1,-1,0,0,-1};
queue<Node>Q;
void bfs()
{
	Node now,last;
	while(!Q.empty())
	{
		last=Q.front();
		Q.pop();
		int hx=last.x;
		int hy=last.y;
		int hm=last.minute;
		int ht=last.ckl;
		if(hx==u && hy==v)
		{
			printf("%d\n",hm);
			return ;
		}
		for(int i=0;i<4;i++)
		{
			now.x=hx+dir[i][0];
			now.y=hy+dir[i][1];
			if(now.x>=0 && now.x<m && now.y>=0 && now.y<n)
			{
				if(g[now.x][now.y]=='#' && !vis[now.x][now.y][now.ckl] && now.ckl>0)
				{
					Node w1;
					w1.x=now.x;
					w1.y=now.y;
					w1.minute=now.minute+1;
					w1.ckl=now.ckl-1;
					Q.push(w1);
			  	vis[now.x][now.y][now.ckl]=1;
				}
				if(g[now.x][now.y]!='#' && !vis[now.x][now.y][now.ckl] )
				{
					Node w1;
					w1.x=now.x;
					w1.y=now.y;
					w1.minute=now.minute+1;
					w1.ckl=now.ckl;	
					Q.push(w1);
					vis[now.x][now.y][now.ckl]=1;
				
				}
			}
		}
	}
	puts("-1");
}
int main()
{
    scanf("%d%d%d",&m,&n,&t);
	memset(vis,0,sizeof(vis));
	while(!Q.empty())
         Q.pop();
	for(int i=0;i<m;i++)
	{
		scanf("%s",g[i]);
	}
    for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
	  { 
		if(g[i][j]=='@')
	    {
        Node w;
        w.x=i;
        w.y=j;
        w.minute=0;
        w.ckl=t;
        vis[i][j][t]=1;
        Q.push(w);
	    }
		if(g[i][j]=='+')
	    {
			u=i;
			v=j;
     	}
	  }
	}
	bfs();		
	return 0;
}

注意:

1.二维数组的读入方式。不确定可以先输出看看是否正确。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值