P4442
一道最短路的变形题。
首先,把传送的过程拆开,就是先射两枪,再走到一个传送门,传送到另一个传送门,共花费
所以一共有两种走法:一种是走到相邻的格子(spfa 即可),一种是传送。
对于传送,在搜索时枚举起点传送门和终点传送门。在 spfa 之前
注意:不一定是要挨着墙才能传送,会
const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int n,m,sx,sy,tx,ty,vis[N][N],dis[N][N],b[N][N][4];
char ch[N][N];
struct node
{
int x,y;
};
void bfs()
{
memset(dis,0x3f,sizeof dis),dis[sx][sy]=0;
queue<node> q;q.push({sx,sy}),vis[sx][sy]=1;
while(!q.empty())
{
node f=q.front();q.pop(),vis[f.x][f.y]=0;
for(int i=0;i<4;i++)//走到相邻格子
{
int nx=f.x+dx[i],ny=f.y+dy[i];
if(ch[nx][ny]!='#'&&dis[f.x][f.y]+1<dis[nx][ny])
{
dis[nx][ny]=dis[f.x][f.y]+1;
if(!vis[nx][ny])
q.push({nx,ny}),vis[nx][ny]=1;
}
}
for(int i=0;i<4;i++)//传送,枚举终点
{
int d=b[f.x][f.y][i],minn=INF,nx=f.x+dx[i]*d,ny=f.y+dy[i]*d;
for(int j=0;j<4;j++)//枚举起点
if(i!=j)
minn=min(minn,b[f.x][f.y][j]);//取最小值转移
minn+=dis[f.x][f.y]+1;
if(dis[nx][ny]>minn)
{
dis[nx][ny]=minn;
if(!vis[nx][ny])
vis[nx][ny]=1,q.push({nx,ny});
}
}
}
}
void solve()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>ch[i][j];
if(ch[i][j]=='C')
sx=i,sy=j;
if(ch[i][j]=='F')
tx=i,ty=j;
}
for(int i=1;i<=n;i++)//预处理墙壁距离
for(int j=m;j;j--)
if(ch[i][j]=='#')
b[i][j][0]=-1;
else
b[i][j][0]=b[i][j+1][0]+1;
for(int j=1;j<=m;j++)
for(int i=n;i;i--)
if(ch[i][j]=='#')
b[i][j][1]=-1;
else
b[i][j][1]=b[i+1][j][1]+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(ch[i][j]=='#')
b[i][j][2]=-1;
else
b[i][j][2]=b[i][j-1][2]+1;
for(int j=1;j<=m;j++)
for(int i=1;i<=n;i++)
if(ch[i][j]=='#')
b[i][j][3]=-1;
else
b[i][j][3]=b[i-1][j][3]+1;
bfs();
if(dis[tx][ty]==INF)
puts("nemoguce");
else
write(dis[tx][ty],"");
}