HDU -- 2612 Find away

最近学动态规划真是学的太心累了,动态规划很多题目都很难啊。
今天换换脑子,来写一道航电OJ的题目。这题目是用BFS的。
题目相对比leetcode还是有难度的。

原题如下

Find a way
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 28864 Accepted Submission(s): 9297
Problem Description
Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki.
Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city. So yifenfei made arrangements with Merceki to meet at a KFC. There are many KFC in Ningbo, they want to choose one that let the total time to it be most smallest.
Now give you a Ningbo map, Both yifenfei and Merceki can move up, down ,left, right to the adjacent road by cost 11 minutes.

Input
The input contains multiple test cases.
Each test case include, first two integers n, m. (2<=n,m<=200).
Next n lines, each line included m character.
‘Y’ express yifenfei initial position.
‘M’ express Merceki initial position.
‘#’ forbid road;
‘.’ Road.
‘@’ KCF

Output
For each test case output the minimum total time that both yifenfei and Merceki to arrival one of KFC.You may sure there is always have a KFC that can let them meet.

Sample Input
4 4
Y.#@

.#…
@…M
4 4
Y.#@

.#…
@#.M
5 5
Y…@.
.#…
.#…
@…M.
#…#

Sample Output
66
88
66

先花时间来读题目,并理解一下,我说一下大意,两个朋友相约在KFC见面,他们的位置题目也都有给出,分别是Y 和 M。 '.‘代表路,是可以走的,’@‘就代表KFC,有多个,’#'代表路障,即不可走。
每一次走动需要花费11minutes,设计程序输出两人都到达KFC花费一共最短的时间。
这类地图题我们拿到手直接可以考虑DFS 和 BFS。DFS和BFS一定还要考虑剪枝,能剪枝就可以降低复杂度。考虑种种剪枝其实是比较烧脑的。
我们先来看这题,这题我们用BFS来做,BFS叫广度优先搜索,是我学到数据结构图的时候接触到的算法,所以这还是要求前面的基础的,大意就是针对于一个点,将它周围所有最近的点放入队列。然后将最初的点出队列,就这样一次次地放直到遍历完所有点,最后也就是队列空,就是 head == rear 的状态了。BFS是要用到queue的思想的。DFS是递归,递归则是栈处理。
我简易讲一下队列,队列(queue)是一种基本的数据结构,可以用数组和链表实现,队列是一种先进先出的数据结构,队列插入元素的话使用尾插法,即rear++。删除元素的话就是head++.才开始学循环队列的时候好像有个坑需要注意,就是判断队列满,是需要取余,(q->rear+1)%q->maxsize==q->head。这种情况就是队列满。
DFS的优势在于可以遍历所有的可能,如果题目要求你找出所有的可能,那当然要用DFS了,这个要视题目的情况而定。
我们继续看题,这题的话只用一个BFS是显然不可能的,因为有两个人,所以用两次BFS,但是我们需要注意的是,我们怎样才能得到最短之和?我们可以设立一个二位数组,将第二次BFS的结果与第一次叠加。然后找到总和最小的,这样就可以了。注意两次BFS,我们BFS是需要visited这个数组来判定点有没有标记的,那么第二次我们肯定要memset将visited数组再次全部置0,这个小细节不要忘了。
我们这题需要建立对于每个点的结构体,每个结构体可以有三个元素,分别是x,y坐标和距离。

下面上代码。

#include<stdio.h>
#include<string.h>
#define inf (~(0x1<<31))

int ans[1000][1000];  
char map[1000][1000];
int visited[1000][1000];
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
int m,n;

typedef struct Queue
{
	int x;
	int y;
	int s;
 }q;
q queue[1000];
 
void BFS(int startx,int starty)
{
	int head,rear;
	int xx,yy,i;
	head = rear = 0;
	queue[rear].x = startx;
	queue[rear].y = starty;
	queue[rear].s = 0;
	rear++; 
	visited[startx][starty] = 1;
	while(head < rear)
	{
		for(i = 0; i<4; i++)
		{
			xx = dir[i][0] + queue[head].x;
			yy = dir[i][1] + queue[head].y;
			if(visited[xx][yy] || map[xx][yy] == '#' || xx < 0 || xx >= m || yy < 0 || yy >= n)
			continue;
			if(map[xx][yy] == '@')
			{
				ans[xx][yy] += queue[head].s + 11;
			}
			visited[xx][yy] = 1;
			queue[rear].x = xx;
			queue[rear].y = yy;
			queue[rear].s = queue[head].s + 11;
			rear++;
		}
		head++;
	 } 
}

int main()
{
	int i,j;
	while(scanf("%d%d",&m,&n) != EOF)
	{
		memset(visited,0,sizeof(visited));
		memset(ans,0,sizeof(ans));
	    for(i=0;i<m;i++)
	    scanf("%s",map[i]);
	    int x,y;
	    for(i=0; i<m; i++)
	    {
	    	for(j=0; j<n; j++)
	    	{
	    		if(map[i][j] == 'Y')
	    		{
	    			x = i;
	    			y = j;
				}
			}
		}
		BFS(x,y);
		memset(visited, 0, sizeof(visited));
		for(i=0; i<m; i++)
	    {
	    	for(j=0; j<n; j++)
	    	{
	    		if(map[i][j] == 'M')
	    		{
	    			x = i;
	    			y = j;
				}
			}
		}
		BFS(x,y);
		int min = inf;
		for(i=0; i<m; i++)
		{
			for(j=0; j<n; j++)
			{
				if(ans[i][j] < min && ans[i][j])
				min = ans[i][j];
			}
		}
	printf("%d\n",min);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值