问题描述:
CYJ想找到他的小伙伴FPJ,.CYJ和FPJ现在位于一个房间里,这个房间的布置可以看成一个N行M列的矩阵,矩阵内的每一个元素会是下列情况中的一种:
1.障碍区域—这里有一堵墙(用‘#’表示).
2.这是CYJ最开始在的区域(用‘C’表示).
3.这是FPJ在的区域(用‘F’表示).
4.空区域(用‘.’表示).
CYJ携带了一个所谓传送枪的东西,这是一把可以创造传送门的枪械,在每一次行动中,他可以选择下列操作中的一项:
1.移向一个相邻的格子中(上,下,左,右,不能移到墙在的格子里).这个操作要消耗一个单位的时间.
2.转向一个墙(不需要相邻,只需面向即可),向其发射传送门,传送门会留在墙内面向你的地方(至多只能同时存在两扇传送门),若墙上已经有两扇传送门,而你发射了第三扇,那么最初发射的那一扇会消失。同时,你无法在一个位置制造两扇传送门(这个操作不会耗费时间)。
3.如果他与一块墙壁相邻且面前有一扇传送门,那么他可以移动到另一扇传送门前方的格子。这个操作会耗费一个单位的时间.
CYJ想要知道自己最少需要多少时间才能够从起点(‘C’)到达终点(‘F’).
请注意:我们保证地图边缘会是一圈墙壁且一定存在‘C’,‘F’.
输入
第一行输入两个正整数 N 和 M ,(4 ≤ N,M ≤ 500).表示地图大小。
接下来的N行每行一个长度为M的字符串.表示地形。
输出:
你需要输出最少的到达终点的时间,如果不能到达请输出”no”。
样例输入:
6 8
########
#.##…F#
#C.##…#
#…#…#
#…##
########
输出样例:
4
样例 解释:
从C点(3,2)开始,我们首先向左发射传送门,再向下发射传送门,向左进入传送门,到达(5,2),向右发射传送门,向下进入传送门,到达(5,6),向上发射传送门,向右进入传送门,到达(2,6),向右移动,到达F.
数据范围:
50%的数据满足:4<= N,M <=15;
100%的数据满足:4<= N,M <=500;
题解:行动可以分为两种:
- 步行,花费一个单位的时间移动到4联通的相邻格子中去.
- 使用传送门,指定一个方向的墙的前面的一个格子,步行至最近的一个墙的面前,使用传送门传送.花费的时间为到达最近墙面前花费的时间+1.
两种行动相组合即可组成任意行动过程.那BFS求出最近的墙的距离,预处理上下左右的第一面墙前的格子.然后建图用DJ跑最短路即可.复杂度为O(MNlog(NM))。
code:
#include<bits/stdc++.h>
using namespace std;
int n,m,st,ed,len=0;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
char s[550][550];
int b[550][550],Left[550][550],Right[550][550],Under[550][550],Above[550][550],vis[511111],d[511111],lin[511111];
struct node{
int y,v,nxt;
}e[511111*5];
struct Dijk{
int v,x;
bool operator <(const Dijk &a) const{
return a.v < v;
}
};
inline int num(int i,int j) {return (i-1)*m+j;}
queue<pair<int,int> >q;
void bfs()
{
while(q.size())
{
int x=q.front().first,y=q.front().second; q.pop();
for(int i=0;i<4;i++)
{
int tox=x+dx[i],toy=y+dy[i];
if(s[tox][toy]=='.' && !b[tox][toy])
{
b[tox][toy]=b[x][y]+1;
q.push(make_pair(tox,toy));
}
}
}
}
void pre()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(s[i][j]=='#') continue;
if(s[i-1][j]=='#') Above[i][j]=num(i,j);
else Above[i][j]=Above[i-1][j];
if(s[i][j-1]=='#') Left[i][j]=num(i,j);
else Left[i][j]=Left[i][j-1];
}
for(int i=n;i>=1;i--)
for(int j=m;j>=1;j--)
{
if(s[i][j]=='#') continue;
if(s[i+1][j]=='#') Under[i][j]=num(i,j);
else Under[i][j]=Under[i+1][j];
if(s[i][j+1]=='#') Right[i][j]=num(i,j);
else Right[i][j]=Right[i][j+1];
}
}
void ins(int x,int y,int v) { e[++len].nxt=lin[x]; lin[x]=len; e[len].y=y; e[len].v=v; }
void make_node()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(s[i][j]=='#') continue;
if(s[i+1][j]=='.') ins(num(i,j),num(i+1,j),1),ins(num(i+1,j),num(i,j),1);
if(s[i][j+1]=='.') ins(num(i,j),num(i,j+1),1),ins(num(i,j+1),num(i,j),1);
if(Left[i][j]!=num(i,j)) ins(num(i,j),Left[i][j],b[i][j]);
if(Right[i][j]!=num(i,j)) ins(num(i,j),Right[i][j],b[i][j]);
if(Under[i][j]!=num(i,j)) ins(num(i,j),Under[i][j],b[i][j]);
if(Above[i][j]!=num(i,j)) ins(num(i,j),Above[i][j],b[i][j]);
}
}
priority_queue<Dijk> qe;
void Dijsktra()
{
qe.push((Dijk){0,st}); d[st]=0;
while(qe.size())
{
int x=qe.top().x,v=qe.top().v; qe.pop();
if(vis[x]) continue; vis[x]=1;
for(int i=lin[x];i;i=e[i].nxt)
{
int y=e[i].y;
if(v+e[i].v<d[y]) d[y]=v+e[i].v,qe.push((Dijk){d[y],y});
}
}
}
int main()
{
freopen("cell.in","r",stdin);
freopen("cell.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>s[i][j];
if(s[i][j]=='C') st=num(i,j),s[i][j]='.';
if(s[i][j]=='F') ed=num(i,j),s[i][j]='.';
if(s[i][j]=='#') q.push(make_pair(i,j));
}
bfs();
pre();
make_node();
memset(d,10,sizeof(d));
Dijsktra();
if(d[ed]==168430090) cout<<"no";
else cout<<d[ed];
return 0;
}