USACO 2.3.1 跨越栅栏
by MPS
====================================================================================
在此,感谢@NOIRP大牛的思路提醒,给了我出发点,使我最终解决了这题。
====================================================================================
【题目描述】
给定迷宫的宽W(1<=W<=38)及长H(1<=H<=100)。
2*H+1行,每行2*W+1的字符以下面给出的格式表示一个迷宫。然后计算从迷宫中最“糟糕”的那一个点走出迷宫所需的步数。(即使从这一点以最优的方式走向最靠近的出口,它仍然需要最多的步数)当然了,牛们只会水平或垂直地在X或Y轴上移动,他们从来不走对角线。每移动到一个新的方格算作一步(包括移出迷宫的那一步)
这是一个W=5,H=3的迷宫:
如上图的例子,栅栏的柱子只出现在奇数行或奇数列。每个迷宫只有两个出口。
农夫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;
}