USACO 2.3.1 跨越栅栏

USACO 2.3.1 跨越栅栏
by MPS
====================================================================================
在此,感谢@NOIRP大牛的思路提醒,给了我出发点,使我最终解决了这题。
====================================================================================
【题目描述】

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

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

【输入描述】                                                                                                                               【输出描述】

第一行,W和H                                                                                                                               最糟糕的点所需要的步数
第二行至第2*H+1行,每行2*M+1个字符,构成这个迷宫
【样例输入】                                                                                                                               【样例输出】                                                              
5 3                                                                                                                      9((6,2)为最糟糕点)
+-+-+-+-+-+
|                |
+-+ +-+ + +
|         |  |  |
+ +-+-+ + +
|  |         |  
+-+ +-+-+-+
 

【分析】

也许是我太渣渣了,一开始居然想枚举每一个点,然后跑一遍BFS,结果TLE了7个点...然后拿去问@NOIRP,他看了一下,就机智地说反向BFS,我想了一下,就知道应该以两个出口分别为起点,跑一遍BFS,然后就AC了,注意这题有几个坑:

   (1)每次前进2格,为什么这么说呢?比如说上图:不能走有+号的一行,因为那行实际不存在(想一想,为什么?)

   (2)是2*...不要数组开小了....

   (3)不能直接以起点BFS,因为要考虑到第(1)个坑,每次走到偶数格,所以要特殊处理起点,如果起点是(2,1)则应改为(2,2)(想一想,为什么?),其余以此类推

    想清楚这几点以后,基本上就能AC了


【代码】

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cctype>
#include <cstring>
#include <string>
#include <cstdlib>
#include <vector>
#include <queue>
#include <deque>
using namespace std;

const int MaxN=203;

struct xOy{
	int x,y;
};

int vis[MaxN][MaxN];
char maze[MaxN][MaxN];
int n,m,ans;
int out1x,out2x,out1y,out2y;

void readfile(){
	int i,j;
	char c;
	scanf("%d%d",&m,&n);
	m=m*2+1;n=n*2+1;
	for(i=1;i<=n;i++)
	  for(j=1;j<=m;j++){
	    scanf("%c",&c);
		if(c=='\n')scanf("%c",&c);
		maze[i][j]=c;
	  	if((j==m || j==1 || i==n || i==1)&& maze[i][j]==' ' && out1x==0 && out1y==0)out1x=i,out1y=j;
	  	if((i==n || i==1 || j==1 || j==m)&& maze[i][j]==' ')out2x=i,out2y=j;
	  }
}

queue<xOy> q;
void bfs(int x,int y){
	vis[x][y]=0;
	if(y==m)y--;
	if(y==1)y++;
	if(x==n)x--;
	if(x==1)x++;
	vis[x][y]=1;
    q.push((struct xOy){x,y});
    int headx,heady;
	while(!q.empty()){
    	headx=q.front().x;
    	heady=q.front().y;
    	q.pop();//拓展四个方向↓
    	if((headx+2<=n) && maze[headx+1][heady]==' ' && vis[headx+2][heady]>vis[headx][heady]+1){q.push((struct xOy){headx+2,heady});vis[headx+2][heady]=vis[headx][heady]+1;}
        if((headx-2>0) && maze[headx-1][heady]==' ' && vis[headx-2][heady]>vis[headx][heady]+1){q.push((struct xOy){headx-2,heady});vis[headx-2][heady]=vis[headx][heady]+1;}
        if((heady+2<=m) && maze[headx][heady+1]==' ' && vis[headx][heady+2]>vis[headx][heady]+1){q.push((struct xOy){headx,heady+2});vis[headx][heady+2]=vis[headx][heady]+1;}
        if((heady-2>0) && maze[headx][heady-1]==' ' && vis[headx][heady-2]>vis[headx][heady]+1){q.push((struct xOy){headx,heady-2});vis[headx][heady-2]=vis[headx][heady]+1;}
	}
}

void solve(){
	int i,j,ans=0;
	memset(vis,0x7F,sizeof(vis));
	bfs(out1x,out1y);
	bfs(out2x,out2y);
	for(i=2;i<=n;i+=2)//只能走偶数格,不然的话会出现结果=0x7F
	  for(j=2;j<=m;j+=2)
	    if(maze[i][j]==' ' && vis[i][j]>ans)ans=vis[i][j];
	printf("%d",ans);
}

int main(){
  freopen("maze1.in","r",stdin);
  freopen("maze1.out","w",stdout);
  readfile();
  solve();
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值