题目描述
亚马逊雨林实在是太大了,小X和他的小弟们进去一会儿就迷路了,然而大雨已经来临,冲刷了一些道路,小X凭借他最后的5%的电量给你发来一条求助信息,希望你帮助他们逃出困境……
小X给你发来一张n×m的地图,每一个点有4种情况。
“0”:此地方可以走。
“1”:此地方不可以走。
“2”:此地方有一种凶恶的野兽。
“3”:此地方为传送地域。
野兽会不定时地苏醒过来,此阶段该处就不能走。 暴雨会不定时地冲刷一些地区,这些地区从今往后不可以行走,也不可以传送到。 传送地域之间可以互相传送,即可以从一个传送门传送到任何一个其他的传送门。 小X和他的小弟们现在位于(1,1),他们希望在(n,m)点逃出雨林。 他们只能前后左右移动,每移动一次需要花费1个单位的时间,传送一次需要花费2个单位的时间,也可以选择不传送。 注意:若下一秒某地区暴雨即将冲刷/野兽即将醒来,则不可以通行,也不可停留在这个这个地区。 在任意时刻,他们可以选择不进行任何操作。
输入格式
第一行两个整数n,m,表示一张n×m的地图。
接下来n行,每行m个整数,为0-3之间的一个数字。
接下来一行一个整数a, 表示接下来a行描述暴雨情况。
接下来a行,每行第一个整数为t,表示此次暴雨在t时刻来临;第二个整数为p,表示此次暴雨冲刷了p个地区;接下来p组整数,每组有(x,y)两个整数,表示(x,y)这个地点被冲刷。(假设暴雨冲刷不需要时间,同一个地点可能被暴雨多次冲刷)
接下来b行,每行前两个整数为t1,t2,表示这个野兽在t1-t2时刻是苏醒的。
接下来两个整数x,y,表示野兽位于x,y位置。(保证(x,y)=2) 不保证所有的野兽均会有苏醒的时刻 保证:(1,1)=(n,m)=0且永远不会被暴雨冲刷。
输出格式
一行一个整数,即最短逃脱时间。 (保证小X和他的小弟们可以逃脱亚马逊雨林)
样例
输入样例
3 3
0 1 0
2 0 1
3 2 0
2
2 1 3 1
1 1 1 3
1
2 4 2 1
输出样例
4
数据范围与提示
时刻1,暴雨冲刷了1,3这个位置。 时刻2,暴雨冲刷了3,1这个位置。 时刻2-4,位于(2,1)的野兽苏醒了。 小X与他的小弟们的逃脱路线: (1,1)->(2,1)->(2,2)->(3,2)->(3,3)
对于100%的数据,n≤300,m≤300,t≤10000。
思路
这题暴力BFS就好了,但是码量有亦点点的大。
BFS是可以重复入队的,但为了不让他们反复横跳,就要判断时间,取时间的较小值。注意,只有时间发生改变了需要入队。
BFS内部要分类:
-
处理传送门(注意:传送门会被洪水冲坏)
-
判断下一步是否会被洪水干掉/出界/阻挡
-
下一步空地或传送门
1.更新
-
下一步野兽
1.判断是否等待(不等待就更新,等待就进入下一步)
2.判断等待是会不会被干掉(野兽或洪水)
3.更新(记得加上等待时间)
注意,更新都需要判断时间 共169行,请勿COPY!!!
CODE
#include<bits/stdc++.h>
using namespace std;
int ax[5]={0,1,-1,0,0},ay[5]={0,0,0,1,-1};
int mp[400][400],tim[400][400],fx[90010],fy[90010];
int cnt;
struct node
{
int x,y;
}csm[90005];
struct node1
{
int st,en,many;
}eat[400][400];
int n,ys,by,m,rain[400][400];
void in()//输入
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&mp[i][j]);
if(mp[i][j]==3)
{
cnt++;
csm[cnt].x=i;
csm[cnt].y=j;
}
}
}
//地图和传送门
scanf("%d",&by);
for(int i=1;i<=by;i++)
{
int t,p;
scanf("%d%d",&t,&p);
for(int j=1;j<=p;j++)
{
int x,y;
scanf("%d%d",&x,&y);
if(rain[x][y])
{
rain[x][y]=min(rain[x][y],t);
}
else
{
rain[x][y]=t;
}
}
}
//暴雨
scanf("%d",&ys);
for(int j=1;j<=ys;j++)
{
int x,y,t1,t2;
scanf("%d%d%d%d",&t1,&t2,&x,&y);
eat[x][y].many++;
eat[x][y].st=t1;
eat[x][y].en=t2;
}
//野兽
}
int wait(int x,int y,int t,int x1,int y1)//等待时间
{
int k=0;
if(eat[x][y].st<=t&&eat[x][y].en>=t)
{
int tmp=eat[x][y].en+1;
if(rain[x1][y1]<=tmp&&rain[x1][y1]) return -1;//洪水
else if(eat[x1][y1].st<=tmp&&eat[x1][y1].en>=tmp) return -1;//野兽
else return tmp-t;//返回等待时间
}
else return 0;//不须等待
}
void bfs(int x,int y)
{
int t=0,w=1;
fx[w]=x;
fy[w]=y;
while(t<w)
{
t++;
if(mp[fx[t]][fy[t]]==3)//当前传送门!!!
{
for(int i=1;i<=cnt;i++)
{
if(rain[csm[i].x][csm[i].y]&&rain[csm[i].x][csm[i].y]<=tim[fx[t]][fy[t]]+2) continue;//被洪水冲垮了
if(tim[csm[i].x][csm[i].y]==0)
{
tim[csm[i].x][csm[i].y]=tim[fx[t]][fy[t]]+2;
w++;
fx[w]=csm[i].x;
fy[w]=csm[i].y;
}
else if(tim[csm[i].x][csm[i].y]>0)
{
if(tim[csm[i].x][csm[i].y]>tim[fx[t]][fy[t]]+2)
{
tim[csm[i].x][csm[i].y]=tim[fx[t]][fy[t]]+2;
w++;
fx[w]=csm[i].x;
fy[w]=csm[i].y;
}
}//更新
}
}
for(int i=1;i<=4;i++)
{
x=fx[t]+ax[i];
y=fy[t]+ay[i];//下一步
if(x<=0||y<=0||x>n||y>m) continue;//出界
if(mp[x][y]==1) continue;//阻挡
if(rain[x][y]<=tim[fx[t]][fy[t]]+1&&rain[x][y]) continue;//洪水
if(mp[x][y]==2)//野兽
{
int tmp=wait(x,y,tim[fx[t]][fy[t]]+1,fx[t],fy[t]);//计算等待时间
if(tmp==-1) continue;//此路不通
else
{
if(tim[x][y]==0&&(x!=1||y!=1))//判断为0
{
w++;
fx[w]=x;
fy[w]=y;
tim[x][y]=tim[fx[t]][fy[t]]+1+tmp;
}
else
{
if(tim[x][y]>tim[fx[t]][fy[t]]+1+tmp)//时间
{
tim[x][y]=tim[fx[t]][fy[t]]+1+tmp;
w++;
fx[w]=x;
fy[w]=y;
}
}//更新
}
}
else if(mp[x][y]==0||mp[x][y]==3)//空地和传送门(下一步)
{
if(tim[x][y]==0&&(x!=1||y!=1))//判断为0
{
w++;
fx[w]=x;
fy[w]=y;
tim[x][y]=tim[fx[t]][fy[t]]+1;
}
else if(x!=1||y!=1)
{
if(tim[x][y]>tim[fx[t]][fy[t]]+1)//时间
{
tim[x][y]=tim[fx[t]][fy[t]]+1;
w++;
fx[w]=x;
fy[w]=y;
}
}
}
}
}
}
int main()
{
in();
bfs(1,1);
printf("%d",tim[n][m]);
}