博弈搜索练习-BFS&DFS

A - Oil Deposits

The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.  
Input
The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either `*', representing the absence of oil, or `@', representing an oil pocket.
Output
For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.
Sample Input
1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5 
****@
*@@*@
*@**@
@@@*@
@@**@
0 0 
Sample Output
0
1
2
2

题意:就是要你找出有几块石油田,凡是上下左右及斜方向一位有‘@’的均属于同一个石油田。
题解:就是用BFS按题意找就好,凡是找过的重新改成‘*’。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int Map_m, Map_n;
char StrMap[102][102] = { '\0' };
int trend[8][2] = { {0,1},{0,-1},{1,0},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1} };
struct Point
{
	int x, y;
};

void BFS(int x,int y)
{
	Point st,k,t;
	queue<Point>q;
	st.x = x; st.y = y;
	q.push(st);
	while (!q.empty())
	{
		t=q.front();
		q.pop();
		if (StrMap[t.x][t.y] == '@')//必须从有‘@’的地方开始8个方向查找
		{
			StrMap[t.x][t.y] = '*';
			for (int i = 0; i < 8; i++)
			{
				k.x = t.x + trend[i][0];
				k.y = t.y + trend[i][1];
				if (k.x < Map_m&&k.x >= 0 && k.y >= 0 && k.y < Map_n)
					q.push(k);
			}
		}
	}
}

int main()
{
	int count;
	while (~scanf("%d %d", &Map_m, &Map_n) && (Map_m*Map_n != 0))
	{
		memset(StrMap, '\0', sizeof(StrMap));
		count = 0;
		for (int i = 0; i < Map_m; i++)
		{
			scanf("%s", StrMap[i]);
		}
		for (int i = 0; i < Map_m; i++)
		{
			for (int j = 0; j < Map_n; j++)
			{
				if (StrMap[i][j] == '@')
				{
					BFS(i, j);
					count++;
				}
			}
		}
		printf("%d\n", count);
	}
	return 0;
}


B - Nightmare

  Ignatius had a nightmare last night. He found himself in a labyrinth with a time bomb on him. The labyrinth has an exit, Ignatius should get out of the labyrinth before the bomb explodes. The initial exploding time of the bomb is set to 6 minutes. To prevent the bomb from exploding by shake, Ignatius had to move slowly, that is to move from one area to the nearest area(that is, if Ignatius stands on (x,y) now, he could only on (x+1,y), (x-1,y), (x,y+1), or (x,y-1) in the next minute) takes him 1 minute. Some area in the labyrinth contains a Bomb-Reset-Equipment. They could reset the exploding time to 6 minutes.

Given the layout of the labyrinth and Ignatius' start position, please tell Ignatius whether he could get out of the labyrinth, if he could, output the minimum time that he has to use to find the exit of the labyrinth, else output -1.

Here are some rules:
1. We can assume the labyrinth is a 2 array.
2. Each minute, Ignatius could only get to one of the nearest area, and he should not walk out of the border, of course he could not walk on a wall, too.
3. If Ignatius get to the exit when the exploding time turns to 0, he can't get out of the labyrinth.
4. If Ignatius get to the area which contains Bomb-Rest-Equipment when the exploding time turns to 0, he can't use the equipment to reset the bomb.
5. A Bomb-Reset-Equipment can be used as many times as you wish, if it is needed, Ignatius can get to any areas in the labyrinth as many times as you wish.
6. The time to reset the exploding time can be ignore, in other words, if Ignatius get to an area which contain Bomb-Rest-Equipment, and the exploding time is larger than 0, the exploding time would be reset to 6.
Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case starts with two integers N and M(1<=N,Mm=8) which indicate the size of the labyrinth. Then N lines follow, each line contains M integers. The array indicates the layout of the labyrinth.
There are five integers which indicate the different type of area in the labyrinth:
0: The area is a wall, Ignatius should not walk on it.
1: The area contains nothing, Ignatius can walk on it.
2: Ignatius' start position, Ignatius starts his escape from this position.
3: The exit of the labyrinth, Ignatius' target position.
4: The area contains a Bomb-Reset-Equipment, Ignatius can delay the exploding time by walking to these areas.
Output
For each test case, if Ignatius can get out of the labyrinth, you should output the minimum time he needs, else you should just output -1.
Sample Input
3
3 3
2 1 1
1 1 0
1 1 3
4 8
2 1 1 0 1 1 1 0
1 0 4 1 1 0 4 1
1 0 0 0 0 0 0 1
1 1 1 4 1 1 1 3
5 8
1 2 1 1 1 1 1 4 
1 0 0 0 1 0 0 1 
1 4 1 0 1 1 0 1 
1 0 0 0 0 3 0 1 
1 1 4 1 1 1 1 1 
Sample Output
4
-1
13
题意:你要从2的地方开始走到3的地方,并且你只有6秒钟的时间,1为普通道路,每走一步耗1秒,4为时间重置的地方,即走到有4的地方你的剩余时间可以被重置为6秒,如果成功走得到3的地方,输出耗时,否则输出-1.
题解: 这题难点在于可以重复走以前走过的道路,所以不能对道路进行标记,于是把这个对道路的边界条件改为对时间的边界条件判断,即只要当前步时间>0就可以入队,其余的和普通BFS差不多。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

int Map_m, Map_n;
int StrMap[10][10];
int trend[4][2] = { {0,1},{0,-1},{1,0},{-1,0} };

struct Point
{
	int x, y;
	int time;
	int step;
};
Point st;

int BFS()
{
	queue<Point>q;
	Point t, k;
	q.push(st);
	while (!q.empty())
	{
		t = q.front(), q.pop();
		if (StrMap[t.x][t.y] == 3)
			return t.step;
		for (int i = 0; i < 4; i++)
		{
			k.x = t.x + trend[i][0];
			k.y = t.y + trend[i][1];
			k.step = t.step + 1;
			k.time = t.time - 1;
			if (k.x >= 0 && k.x < Map_m&&k.y >= 0 && k.y < Map_n&&StrMap[k.x][k.y] != 0 && k.time>0)
			{
				if (StrMap[k.x][k.y] == 4)
				{
					k.time = 6;
					StrMap[k.x][k.y] = 0;
				}
				q.push(k);
			}
		}
	}
	return -1;
}

int main()
{
	int count;
	scanf("%d", &count);
	while (count--)
	{
		memset(StrMap, 0, sizeof(StrMap));
		scanf("%d %d", &Map_m, &Map_n);
		for (int i = 0; i < Map_m; i++)
			for (int j = 0; j < Map_n; j++)
			{
				scanf("%d", &StrMap[i][j]);
				if (StrMap[i][j] == 2)
				{
					st.x = i; st.y = j;
					st.step = 0; st.time = 6;
					StrMap[i][j] = 0;
				}
			}
		int ans = BFS();
		printf("%d\n", ans);
	}
	return 0;
}



 

C - Ignatius and the Princess I

The Princess has been abducted by the BEelzebub feng5166, our hero Ignatius has to rescue our pretty Princess. Now he gets into feng5166's castle. The castle is a large labyrinth. To make the problem simply, we assume the labyrinth is a N*M two-dimensional array which left-top corner is (0,0) and right-bottom corner is (N-1,M-1). Ignatius enters at (0,0), and the door to feng5166's room is at (N-1,M-1), that is our target. There are some monsters in the castle, if Ignatius meet them, he has to kill them. Here is some rules:

1.Ignatius can only move in four directions(up, down, left, right), one step per second. A step is defined as follow: if current position is (x,y), after a step, Ignatius can only stand on (x-1,y), (x+1,y), (x,y-1) or (x,y+1).
2.The array is marked with some characters and numbers. We define them like this:
. : The place where Ignatius can walk on.
X : The place is a trap, Ignatius should not walk on it.
n : Here is a monster with n HP(1<=n<=9), if Ignatius walk on it, it takes him n seconds to kill the monster.

Your task is to give out the path which costs minimum seconds for Ignatius to reach target position. You may assume that the start position and the target position will never be a trap, and there will never be a monster at the start position.
Input
The input contains several test cases. Each test case starts with a line contains two numbers N and M(2<=N<=100,2<=M<=100) which indicate the size of the labyrinth. Then a N*M two-dimensional array follows, which describe the whole labyrinth. The input is terminated by the end of file. More details in the Sample Input.
Output
For each test case, you should output "God please help our poor hero." if Ignatius can't reach the target position, or you should output "It takes n seconds to reach the target position, let me show you the way."(n is the minimum seconds), and tell our hero the whole path. Output a line contains "FINISH" after each test case. If there are more than one path, any one is OK in this problem. More details in the Sample Output.
Sample Input
5 6
.XX.1.
..X.2.
2...X.
...XX.
XXXXX.
5 6
.XX.1.
..X.2.
2...X.
...XX.
XXXXX1
5 6
.XX...
..XX1.
2...X.
...XX.
XXXXX.
Sample Output
It takes 13 seconds to reach the target position, let me show you the way.
1s:(0,0)->(1,0)
2s:(1,0)->(1,1)
3s:(1,1)->(2,1)
4s:(2,1)->(2,2)
5s:(2,2)->(2,3)
6s:(2,3)->(1,3)
7s:(1,3)->(1,4)
8s:FIGHT AT (1,4)
9s:FIGHT AT (1,4)
10s:(1,4)->(1,5)
11s:(1,5)->(2,5)
12s:(2,5)->(3,5)
13s:(3,5)->(4,5)
FINISH
It takes 14 seconds to reach the target position, let me show you the way.
1s:(0,0)->(1,0)
2s:(1,0)->(1,1)
3s:(1,1)->(2,1)
4s:(2,1)->(2,2)
5s:(2,2)->(2,3)
6s:(2,3)->(1,3)
7s:(1,3)->(1,4)
8s:FIGHT AT (1,4)
9s:FIGHT AT (1,4)
10s:(1,4)->(1,5)
11s:(1,5)->(2,5)
12s:(2,5)->(3,5)
13s:(3,5)->(4,5)
14s:FIGHT AT (4,5)
FINISH
God please help our poor hero.
FINISH
题意:从最左上角(0,0)走到最右下角(N-1,M-1),有‘X'的地方不能走,有数字n(1~9)的地方表示你要打怪了,并且打怪要耗时间n,你每走一步也耗时间1秒,输出最短到达时间及路径啥的,具体的标准就对着样例看吧。
题解:这题难点在于要以时间最短,一般的BFS是以路径最短,故处理方式为BFS+优先队列,构建以最短时间的队列并进行BFS,至于输出路径,建个回溯表即可,从终点出发到达起点位置,这样可以用普通循环输出而不必使用栈进行递归输出(个人觉得能不用递归就不用),WA点好像比较少,基本上把3个样例全过就基本上能A了。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

int Map_m, Map_n;
char StrMap[102][102];
int vis[102][102];
int trend[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };

struct node1
{
	int x, y;
	int time;
	bool operator<(const node1 &a) const
	{
		return time>a.time;
	}
};

struct node2
{
	int x, y;
}pass[102][102];//构建回溯表,子节点记录父节点坐标

void Print(node1 ss)//对回溯表进行输出
{
	node2 nt;
	nt.x = ss.x;
	nt.y = ss.y;
	int TIMES = 1;
	for (;;)
	{
		int xx = nt.x, yy = nt.y;
		if (StrMap[nt.x][nt.y] >= '1'&&StrMap[nt.x][nt.y] <= '9')
		{
			int sd = StrMap[nt.x][nt.y] - '0';
			for (int i = 0; i < sd; i++)
				printf("%ds:FIGHT AT (%d,%d)\n", TIMES++,nt.x,nt.y);
		}
		printf("%ds:(%d,%d)->(%d,%d)\n", TIMES++, nt.x, nt.y, pass[nt.x][nt.y].x, pass[nt.x][nt.y].y);
		xx = nt.x; yy = nt.y;
		nt.x = pass[xx][yy].x;
		nt.y = pass[xx][yy].y;
		if (nt.x == Map_m - 1 && nt.y == Map_n - 1)
		{
			if (StrMap[nt.x][nt.y] >= '1'&&StrMap[nt.x][nt.y] <= '9')//这个是debug时发现这块也要加。。。
			{
				int sd = StrMap[nt.x][nt.y] - '0';
				for (int i = 0; i < sd; i++)
					printf("%ds:FIGHT AT (%d,%d)\n", TIMES++, nt.x, nt.y);
			}
			return;
		}	
	}
}

void BFS()
{
	priority_queue<node1>q;
	node1 st, t, k;
	st.x = Map_m - 1; st.y = Map_n - 1;
	st.time = 0;
	vis[st.x][st.y] = 1;
	pass[st.x][st.y].x = Map_m; pass[st.x][st.y].y = Map_n;
	q.push(st);
	while (!q.empty())
	{
		t = q.top();
		q.pop();
		if (t.x == 0 && t.y == 0)
		{
			if (StrMap[st.x][st.y] >= '1'&&StrMap[st.x][st.y] <= '9')//样例2就出现了终点也有怪耗时间的情况
				t.time += StrMap[st.x][st.y] - '0';
			printf("It takes %d seconds to reach the target position, let me show you the way.\n", t.time);
			Print(t);
			return;
		}
		for (int i = 0; i < 4; i++)
		{
			k.x = t.x + trend[i][0];
			k.y = t.y + trend[i][1];
			if (k.x >= 0 && k.x < Map_m&&k.y >= 0 && k.y < Map_n&&vis[k.x][k.y] != 1 && StrMap[k.x][k.y] != 'X')
			{
				if (StrMap[k.x][k.y] >= '1'&&StrMap[k.x][k.y] <= '9')
					k.time = t.time + (StrMap[k.x][k.y] - '0')+1;//打怪耗时间
				else
					k.time = t.time + 1;//正常道路耗时间
				pass[k.x][k.y].x = t.x;//记录父节点
				pass[k.x][k.y].y = t.y;//记录父节点
				vis[k.x][k.y] = 1;
				q.push(k);
			}
		}
	}
	printf("God please help our poor hero.\n");//找不到就说明无法成功到达终点
}

int main()
{
	while (~scanf("%d %d", &Map_m, &Map_n))
	{
		memset(StrMap, '\0', sizeof(StrMap));
		memset(vis, 0, sizeof(vis));
		for (int i = 0; i < Map_m; i++)
			scanf("%s", StrMap[i]);
		BFS();
		printf("FINISH\n");
	}
	return 0;
}

                     













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值