穿越栅栏
(pass.cpp/c/pas)
【问题描述】
FJ搭建了一个巨大的用栅栏围成的迷宫。幸运的是,他在迷宫的边界上留出了两段栅栏作为迷宫的出口,并且从迷宫中的任意一点都能找到一条走出迷宫的路。给定迷宫的行和列数和这个迷宫,然后计算从迷宫中最“糟糕”的那一个点走出迷宫所需的最少步数。
【输入格式】
第一行为正数m和n,表示迷宫的行数和列数,用空格隔开。迷宫用一个由数字组成的矩阵表示,一个数字表示迷宫的一个格子。每一个格子的数字告诉我们这个格子的东、西、南、北是否有栅栏存在。每个数字是由以下四个整数的某个或某几个或一个都没有加起来的。
1: 在西面有栅栏
2: 在北面有栅栏
4: 在东面有栅栏
8: 在南面有栅栏
迷宫内部的栅栏会被规定两次。比如说(1,1)南面的栅栏,亦会被标记为(2,1)北面的栅栏。
最后两行是由出口格子的行列坐标。
【输出格式】
输出一个单独的整数,表示能保证牛从迷宫中任意一点走出迷宫的最小步数。
【输入输出样例】
pass.in pass.out
3 5
11 2 10 2 6
3 8 14 5 5
13 3 10 12 9
3 2
3 5
9
【输入输出样例说明】
样例输入的迷宫如图a,最糟糕的点是左下角的格子,走出迷宫需要9步,见图b。
【数据范围】
1 <= m <= 38
1 <= n <= 100
【来源】
改编自【USACO2.4.2】穿越栅栏
多源BFS,道理同火蔓延的迷宫中找火蔓延的时间。
考试的时候压根没想,看到数据范围直接想到暴力求解,结果就错了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=105;
struct data
{
int a,b;
}q[maxn*maxn*maxn];
int a[maxn][maxn][4]={0},vis[maxn][maxn]={0},d[maxn][maxn]={0};
int n,m,x1,y1,x2,y2,ans=0,front,rear;
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
void in()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
if(x>=8){a[i][j][1]=1;x-=8;}
if(x>=4){a[i][j][0]=1;x-=4;}
if(x>=2){a[i][j][3]=1;x-=2;}
if(x>=1){a[i][j][2]=1;x-=1;}
}
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
}
void bfs()
{
front=rear=1;
q[rear++]=(data){x1,y1};
q[rear++]=(data){x2,y2};
d[x1][y1]=1;
vis[x1][y1]=1;
d[x2][y2]=1;
vis[x2][y2]=1;
while(front!=rear)
{
data t=q[front++];
for(int i=0;i<4;i++)
{
int xx=t.a,yy=t.b;
int nx=xx+dx[i],ny=yy+dy[i];
if(a[xx][yy][i]) continue;
if(nx<1||ny<1||nx>n||ny>m) continue;
if(vis[nx][ny]) continue;
vis[nx][ny]=1;
d[nx][ny]=d[xx][yy]+1;
q[rear++]=(data){nx,ny};
}
}
}
int main()
{
freopen("pass.in","r",stdin);
freopen("pass.out","w",stdout);
in();
bfs();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ans=max(ans,d[i][j]);
printf("%d",ans);
return 0;
}