初学者觉得BFS超难 第一天理解的题 Rescue (BFS) Catch That Cow (BFS)Red and Black(BFS)

Rescue

Angel was caught by the MOLIGPY! He was put in * by Moligpy. The * is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the *. 

Angel's friends want to save Angel. Their task is: approach Angel. We assume that "approach Angel" is to get to the position where Angel stays. When there's a guard in the grid, we must kill him (or her?) to move into the grid. We assume that we moving up, down, right, left takes us 1 unit time, and killing a guard takes 1 unit time, too. And we are strong enough to kill all the guards. 

You have to calculate the minimal time to approach Angel. (We can move only UP, DOWN, LEFT and RIGHT, to the neighbor grid within bound, of course.) 

Input

First line contains two integers stand for N and M. 

Then N lines follows, every line has M characters. "." stands for road, "a" stands for Angel, and "r" stands for each of Angel's friend. 

Process to the end of the file. 

Output

For each test case, your program should output a single integer, standing for the minimal time needed. If such a number does no exist, you should output a line containing "Poor ANGEL has to stay in the * all his life." 

Sample Input

7 8
#.#####.
#.a#..r.
#..#x...
..#..#.#
#...##..
.#......
........

Sample Output

13

翻译:

天使被MOLIGPY抓住了!他被Moligpy监禁了。*被描述为N * M(N,M <= 200)矩阵。*里有WALL,ROAD和GUARD。 

天使的朋友想要拯救天使。他们的任务是:接近天使。我们假设“接近天使”是为了达到安吉尔留下的位置。当网格中有一名后卫时,我们必须杀死他(或她?)才能进入网格。我们假设我们向上,向下,向右,向左移动需要1个单位时间,并且杀死一名守卫也需要1个单位时间。我们足够强大,可以杀死所有的守卫。 

你必须计算接近天使的最短时间。(当然,我们只能将UP,DOWN,LEFT和RIGHT移动到绑定范围内的邻居网格。) 

输入

第一行包含两个整数代表N和M. 

然后是N行,每行有M个字符。“” 代表道路,“a”代表Angel,“r”代表Angel的每个朋友。 

处理到文件的末尾。 

产量

对于每个测试用例,您的程序应输出一个整数,代表所需的最短时间。如果这样的数字不存在,你应该输出一行包含“贫穷的ANGEL必须终生留在*里”。 

这一题是标准的BFS;这里会用到队列queue 队列的特点就是先进先出;

常用方法

  • empty() 判断队列是否为空,返回类型为bool
  • size() 返回队列中元素的个数
  • front() 返回队列队首元素
  • back() 返回队列队尾元素
  • push(ele) 将元素ele插入到队尾
  • pop 队首元素出队

基本的模版要先定义vis二维数组去标记相应的是否走过这个地方,而bfs的思路就是找出所有的路 并且寻找一个最符合要求的

还有一个队列的优先级的函数

//只有<重载操作符函数时,如果将<改为>为什么不行,出现error C2784的错误
	friend bool operator <(Node node1,Node node2)
	{
		//<为从大到小排列,>为从小到大排列
		return node1.key<node2.key;
	}
	friend bool operator >(Node node1,Node node2)
	{
		return node1.key<node2.key;

friend bool operator 函数 <为从大到小,>为从小到大排列。

然后分享一个粗制的bfs模版

#include <bits/stdc++.h>
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll maxN = 300+10; 
int N,M;
string str[maxN]; //面板
bool vis[maxN][maxN]; //访问数组,值为0->未访问,1->访问了
int rute[maxN][maxN]; //跑图的成果,每一个都存的是到此最小的step, 这个表格出来了,想要哪个点,就输出哪个点的最小step,这样的好处就是,无需关心跑图何时应该停止的判断条件(BFS跑图挺快的)
int dir[4][2] = {-1,0,1,0,0,1,0,-1};//方位数组
struct pos{ //结构体
	int x;
	int y;//当前的位置
	int step;//到此位置最小的步数
	friend bool operator < (pos p1,pos p2){
		return p1.step > p2.step;
	}
};
int check(int x,int y){ //检查函数,需要检查边界,是否访问,是否有墙壁, 返回0不能通过,返回1需要走1步,返回2需要走2步
	if(x<0||x>=N||y<0||y>=M||vis[x][y]==1 ||str[x][y] == 'S'||str[x][y]=='R') return 0;
	else if(str[x][y] == 'B') return 2;
	else return 1;
}
int main(){
	#ifdef LOCAL
	freopen("test.in","r",stdin); //用于本地Debug调试
	freopen("test.out","w",stdout);
	#endif
	while(cin>>N>>M&&!(N==0&&M==0)){
		memset(vis,0,sizeof(vis));//每一次跑图都需要归零
		memset(rute,0,sizeof(rute));
		priority_queue<pos> q;//优先队列,最好都用优先队列
		int x1,y1,x2,y2;//起点(x1,y1) 终点(x2,y2)
		for(int i = 0 ;i<N;i++){ //去查找并记录起点、终点的坐标
			cin>>str[i];
			for(int j = 0;j<M;j++){
				if(str[i][j] == 'Y'){
					x1 = i;
					y1 = j;
				}
				if(str[i][j] == 'T'){
					x2 = i;
					y2 = j;
				}
			}
		}
		//将起点放入的队列中
		q.push({x1,y1,0});
		vis[x1][y1] = 1;
		rute[x1][y1] = 0;
		int step;
		pos cur,ne;//当前点current,下一个点next
		while(!q.empty()){
			cur = q.top();//每次取队头
			q.pop();//删队头
			for(int i = 0;i<4;i++){ //开始遍历方位数组进行跑图
				ne.x = cur.x+dir[i][0];
				ne.y = cur.y+dir[i][1];
				if(step = check(ne.x,ne.y)){//检查
					ne.step = cur.step+step;
					q.push(ne);
					vis[ne.x][ne.y] = 1;
					rute[ne.x][ne.y] = ne.step;
				}
			}
		}
		//最后输出终点的step信息
		if(rute[x2][y2]>0)cout<<rute[x2][y2]<<endl;
		else cout<<-1<<endl;
	}	
	return 0;

ac的代码但是有问题 数据太水了。以后有时间再改。

#include <bits/stdc++.h>
#include <queue>
using namespace std;
const int maxn=200+10;
vector<int> G[maxn];
char str[maxn][maxn];
int vis[maxn][maxn];
int m,n;
struct node
{
	int x,y;
	int step;
};
int d[4][2]={1,0,-1,0,0,1,0,-1};
void bfs(int x1,int y1,int x2,int y2)
{
	memset(vis,0,sizeof(vis));
	queue<node> que;
	node e1,e2;
	e1.x=x1,e1.y=y1,e1.step=0;
	que.push(e1);
	vis[x1][y1]=1;
	int ans=0x3f3f3f3f;
	while(!que.empty())
	{
		e1=que.front();
		que.pop();
		if(e1.x==x2&&e1.y==y2)
		{
			ans=min(ans,e1.step);
		}
		for(int i=0;i<4;i++)
		{
			e2.x=e1.x+d[i][0];
			e2.y=e1.y+d[i][1];
		if(e2.x>0&&e2.x<n&&e2.y>0&&e2.y<m&&!vis[e2.x][e2.y]&&str[e2.x][e2.y]!='#')
		{
			if(str[e2.x][e2.y]=='r'||str[e2.x][e2.y]=='.')
			{
				e2.step=e1.step+1;
			}
			else if(str[e2.x][e2.y]=='x')
			{
				e2.step=e1.step+2;
			}
			que.push(e2);
			vis[e2.x][e2.y] = 1;
		}
	}
}
	if(ans == 0x3f3f3f3f) puts("Poor ANGEL has to stay in the * all his life.");
	else printf("%d\n", ans);
}
int main()
{
	int edx,edy,sdx,sdy;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(int i=0;i<n;i++)
		{
			scanf("%s",str[i]);
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(str[i][j]=='a')
				{
					edx=i,edy=j;
				}
				if(str[i][j]=='r')
				{
					sdx=i,sdy=j;
				}
			}
		}
		bfs(edx,edy,sdx,sdy);
	}
	return 0;
}

 Catch That Cow

 

农夫知道一头牛的位置,想要抓住它。农夫和牛都于数轴上 ,农夫起始位于点 N(0<=N<=100000) ,牛位于点 K(0<=K<=100000) 。农夫有两种移动方式: 1、从 X移动到 X-1或X+1 ,每次移动花费一分钟 2、从 X移动到 2*X ,每次移动花费一分钟 假设牛没有意识到农夫的行动,站在原地不。最少要花多少时间才能抓住牛?

Input

一行: 以空格分隔的两个字母: N 和 K

Output

一行: 农夫抓住牛需要的最少时间,单位分钟

Sample Input

5 17

Sample Output

4

Hint

农夫使用最短时间抓住牛的方案如下: 5-10-9-18-17, 需要4分钟.

这一题的思路呢就是bfs然后会有三步 一个是步数+1 一个是步数-1 一个是步数乘以2 然后找到步数最少的那个步骤。如果n>=k的话直接k-n就可以了。

代码如下

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=100001;
bool vis[maxn];//标记数组 
int step[maxn];//记录到了每一位置的步数;
queue <int> q;//定义队列
int bfs(int n,int k)
{
	int head,next;
	q.push(n);
	step[n]=0;
	vis[n]=true;
	while(!q.empty())
	{
		head=q.front();
		q.pop();
		for(int i=0;i<3;i++)
		{
			if(i==0) next=head+1;
			else if(i==1) next=head-1;
			else next=head*2;
			if(next<0 || next>=maxn) continue;//排除出界情况 
			if(!vis[next])//如果next位置未被访问 
			{
				q.push(next);//入队 
				step[next]=step[head]+1;
				vis[next]=true; 
			 } 
			 if(next==k) return step[next];	
		}
	}
 } 
 int main()
 {
 	int n,k;
 	cin>>n>>k;
 	memset(step,0,sizeof(step));
 	memset(vis,false,sizeof(vis));
 	if(n>=k) printf("%d\n",n-k);
 	else printf("%d\n",bfs(n,k));
 	return 0;
 }

There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he can move only on black tiles. 

Write a program to count the number of black tiles which he can reach by repeating the moves described above. 

Input

The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20. 

There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows. 

'.' - a black tile 
'#' - a red tile 
'@' - a man on a black tile(appears exactly once in a data set) 

Output

For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself). 

Sample Input

6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
...@...
###.###
..#.#..
..#.#..
0 0

Sample Output

45
59
6
13

翻译

这间长方形客房铺有方形瓷砖。每个瓷砖都是红色或黑色。一个男人站在黑色的瓷砖上。从瓷砖中,他可以移动到四个相邻瓷砖中的一个。但他不能在红瓦上移动,他只能在黑色瓷砖上移动。

编写一个程序,通过重复上述动作来计算他可以达到的黑色瓷砖的数量。 

输入

输入由多个数据集组成。数据集以包含两个正整数W和H的行开始; W和H分别是x和y方向上的瓦片数量。W和H不超过20. 

数据集中还有H行,每行包含W个字符。每个字符代表一个图块的颜色,如下所示。 

'' - 黑色瓷砖 
'#' - 红色瓷砖 
'@' - 黑色瓷砖上的男人(在数据集中只显示一次) 

产量

对于每个数据集,您的程序应输出一行,其中包含他可以从初始图块(包括其自身)到达的图块数量。 

正常的bfs问题 

#include <bits/stdc++.h>
using namespace std;
int visited[30][30];
char aa[30][30];
int num,n,m,p,q;
int xy[4][2]={1,0,0,1,-1,0,0,-1};
void dfs(int x,int y)
{
	int i,j;
	for(i=0;i<=3;i++)
	{
		int xx=x+xy[i][0];
		int yy=y+xy[i][1];
		if(xx>=0&&xx<n&&yy>=0&&yy<m&&visited[xx][yy]==0&&aa[xx][yy]=='.')
		{
			visited[xx][yy]=1;
			num++;
			dfs(xx,yy);
		}
	}
}
int main()
{
	int i,j;
	while(scanf("%d %d",&m,&n)!=EOF&&m&&n)
	{
		for(i=0;i<n;i++)
		{
			for(j=0;j<m;j++)
			{
				cin>>aa[i][j];
				if(aa[i][j]=='@')
				{
					p=i;
					q=j;
				}
				visited[i][j]=0;
			}
		}
			visited[p][q]=1;
			num=1;
			dfs(p,q);
			printf("%d\n",num);
	}
	return 0;
}

 

上一篇:秦皇岛站2019CCPC A.Angel Beats


下一篇:java获取视频第一帧工具类