USACO / Overfencing(BFS)

Overfencing穿越栅栏

Kolstad and Schrijvers

特别鸣谢lyl提供翻译!


描述 农夫John在外面的田野上搭建了一个巨大的用栅栏围成的迷宫。幸运的是,他在迷宫的边界上留出了两段栅栏作为迷宫的出口。更幸运的是,他所建造的迷宫是一个“完美的”迷宫:即你能从迷宫中的任意一点找到一条走出迷宫的路。给定迷宫的宽度W(1<=W<=38)及高度H(1<=H<=100)。 2*H+1行,每行2*W+1的字符以下面给出的格式表示一个迷宫。然后计算从迷宫中最“糟糕”的那一个点走出迷宫所需的步数(就是从最“糟糕”的一点,走出迷宫的最少步数)。(即使从这一点以最优的方式走向最靠近的出口,它仍然需要最多的步数)当然了,牛们只会水平或垂直地在X或Y轴上移动,他们从来不走对角线。每移动到一个新的方格算作一步(包括移出迷宫的那一步)这是一个W=5,H=3的迷宫:

+-+-+-+-+-+
|         |
+-+ +-+ + +
|     | | |
+ +-+-+ + +
| |     |  
+-+ +-+-+-+

如上图的例子,栅栏的柱子只出现在奇数行或奇数列。每个迷宫只有两个出口。

格式

PROGRAM NAME: maze1

INPUT FORMAT:

(file maze1.in)

第一行: W和H(用空格隔开) 
第二行至第2 * H + 1行:  每行2 * W + 1个字符表示迷宫 

OUTPUT FORMAT:

(file maze1.out)

输出一个单独的整数,表示能保证牛从迷宫中任意一点走出迷宫的最小步数。

SAMPLE INPUT

5 3
+-+-+-+-+-+
|         |
+-+ +-+ + +
|     | | |
+ +-+-+ + +
| |     |  
+-+ +-+-+-+

SAMPLE OUTPUT

9
分析

我们用一个数组记录每个格子四面连通情况,然后从输入文件中读入每条边(判断),维护这个数组。然后分别从两个出口做Flood fill,记录每个格子的最短距离。所有格子的最短距离的最大值为所求。


可以将整个图用2*w+1,2*h+1的布尔数组表示,门口处记为一步,最后统计所有偶数行列,输出max div 2 源码 --Lsylsy2 16:24 2007年8月2日 (CST)


还可以把两个出口分别作为起点,分别将整个地图走两遍,此时求出两次每个点到两个出口的最短距离中短的一个,再找出最短距离最长的一个点。


注意
第一组数据中
+-+
   // 这行是回车,不是空格(本行有3个空格)     另注:这应该就是空格,经检验过。
+-+

小提示:使用广搜实现Flood Fill更快一点 //但是用dfs flood fill也是可以过的 时间也不算慢


补充:可将地图看为一个图,有一个额外的点表示出口,记可以到出口的一个或两个点到出口距离为1,其余的相邻联通点之间距离记为1(用bool数组即可),然后用堆优化的Dijkstra算法,只用一遍,就可求出各点到出口的最短距离,找出其中最长的即可,效率还不错。


华丽分割线

PS: 可以只做一次BFS, 把两个出口同时加入队列。


/*
ID:138_3531
LANG:C++
TASK:maze1
*/


#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <cstring>


using namespace std;


struct Q
{
    int x;
    int y;
}dl[20000];


int n,w,h;
char map[300][100];
int head,tail;
int d[300][100];
int fx[4][2]={{-2,0},{0,2},{2,0},{0,-2}},fy[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
ifstream fin("maze1.in");
ofstream fout("maze1.out");


void input()
{


    fin>>w>>h;
	h=2*h+1;
	w=2*w+1;
	for(int i=1;i<=h;i++)
	{
	    fin.get();			//因为迷宫中有空格' '型字符,所以读入时不能用cin,用cin.get();
		for(int j=1;j<=w;j++)
		{
			map[i][j]=fin.get();
			//cin>>map[i][j];
			if((i==1)&&(map[i][j]==' ')) {tail++;dl[tail].x=i+1;dl[tail].y=j; d[i+1][j]=1;}
			if((i==h)&&(map[i][j]==' ')) {tail++;dl[tail].x=i-1;dl[tail].y=j; d[i-1][j]=1;}
			if((j==1)&&(map[i][j]==' ')) {tail++;dl[tail].x=i;dl[tail].y=j+1; d[i][j+1]=1;}
			if((j==w)&&(map[i][j]==' ')) {tail++;dl[tail].x=i;dl[tail].y=j-1; d[i][j-1]=1;}
		}
	}
}


void bfs(int head,int tail)
{
    int x,y;
    int p,q;
    while(head!=tail)
    {
        head++;
        x=dl[head].x;
        y=dl[head].y;
        for(int i=0;i<=3;i++)
		{
			p=x+fx[i][0];q=y+fx[i][1];
			if((p>0)&&(p<h)&&(q>0)&&(q<w)&&(map[x+fy[i][0]][y+fy[i][1]]==' '))
                       		if(d[p][q]==0)
                		{
                   			tail++;
                    			dl[tail].x=p;
                    			dl[tail].y=q;
                    			d[p][q]=d[x][y]+1;
                		}
		}
    }
    int total=0;
    for(int i=1;i<=h;i++)
		for(int j=1;j<=w;j++)
			total=(d[i][j]>total?d[i][j]:total);
	fout<<total<<endl;
}


int main()
{
    input();
    bfs(head,tail);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值