一、题目
Description
有一副n*m的地图,有n*m块地,每块是下列四种中的一种:
墙:用#表示,墙有4个面,分别是前面,后面,左面,右面。
起点:用C表示,为主角的起点,是一片空地。
终点:用F表示,为主角的目的地,是一片空地。
空地:用 . 表示。
其中除了墙不能穿过,其他地方都能走。
主角有以下3种操作:
1.移动到相邻的前后左右的地方,花费一个单位时间。
2.向前后左右其中一个方向发射子弹,子弹沿直线穿过,打在最近的一堵墙的一面,然后墙的这面就会形成一个开口通往秘密通道。同一时间最多只能有两个开口,若出现有3个开口,出现时间最早的开口会立即消失。该操作不用时间。
3.可以从一个与开口相邻的空地跳进去,进入秘密通道,从另外一个开口正对的空地跳出来。这个过程花费一个单位时间。
地图四周都是墙,问主角最少用多少时间从C走到F。C和F
只会出现一次。
Input
第一行输入两个正整数n,m。
接下来n行,每行m个字符描述地图。
Output
输出1个整数,表示最短时间完成路途。如果无解输出nemoguce
Data Constraint
对于50%的数据,4≤ n,m≤ 15。
对于100%的数据,4≤ n,m≤ 500。
二、分析
先吐槽一下。。两次模拟题就这道最简单了但还是改了一天,真的就是太弱啦!
这道题很容易就会想到搜索,但是这道题n有500之多,所以肯定不可能用搜索。
直接先处理可以到哪些地方连边就好了。不是很难,但是一定要自己动手!
三、代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[505][505];
int b_x,b_y,e_x,e_y;
int ans = 1e9;
int tot ;
int head[250005] , ver[2000005] ,edge[2000005] ,Next[2000005] ,d[250005] ;
queue<int> q;
bool v[250005];
void add(int x,int y,int z) {
ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
}
void spfa(int begin) {
memset(d,0x3f,sizeof(d));
memset(v,0,sizeof(v));
d[begin]=0;
v[begin]=1;
q.push(begin);
while(q.size()) {
int x=q.front();
q.pop();
v[x]=0;
for(int i=head[x]; i; i=Next[i]) {
int y=ver[i],z=edge[i];
if(d[y]>d[x]+z) {
d[y]=d[x]+z;
if(!v[y]) q.push(y),v[y]=1;
}
}
}
}
int f_1(int x,int y,int now){
int be_x = x;
int be_y = y-now;
int en_x = x-now;
int en_y = y;
while(be_x!=en_x&&be_y!=en_y){
if(a[be_x][be_y]=='#') return 1;
be_x --;
be_y ++;
}
return 0;
}
int f_2(int x,int y,int now){
int be_x = x-now;
int be_y = y;
int en_x = x;
int en_y = y+now;
while(be_x!=en_x&&be_y!=en_y){
if(a[be_x][be_y]=='#') return 1;
be_x ++;
be_y ++;
}
return 0;
}
int f_3(int x,int y,int now){
int be_x = x;
int be_y = y+now;
int en_x = x+now;
int en_y = y;
while(be_x!=en_x&&be_y!=en_y){
if(a[be_x][be_y]=='#') return 1;
be_x ++;
be_y --;
}
return 0;
}
int f_4(int x,int y,int now){
int be_x = x+now;
int be_y = y;
int en_x = x;
int en_y = y-now;
while(be_x!=en_x&&be_y!=en_y){
if(a[be_x][be_y]=='#') return 1;
be_x ++;
be_y --;
}
return 0;
}
int much(int x,int y){
int now=1;
while(1){
if(f_1(x,y,now)==1||f_2(x,y,now)==1||f_3(x,y,now)==1||f_4(x,y,now)==1) {
return now;
}
now++;
}
}
int main(){
// freopen("portal.in","r",stdin);
// freopen("portal.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
if(a[i][j]=='C') b_x = i , b_y = j ;
if(a[i][j]=='F') e_x = i , e_y = j ;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]!='#'){
if(a[i-1][j]!='#') add((i-1)*m+j,(i-2)*m+j,1);
if(a[i+1][j]!='#') add((i-1)*m+j,(i)*m+j,1);
if(a[i][j-1]!='#') add((i-1)*m+j,(i-1)*m+j-1,1);
if(a[i][j+1]!='#') add((i-1)*m+j,(i-1)*m+j+1,1);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]!='#'){
int step = much (i,j) ;
int dx=i,dy=j;
while(a[dx][dy]!='#') dx--;
dx++;
add((i-1)*m+j,(dx-1)*m+dy,step);
dx=i,dy=j;
while(a[dx][dy]!='#') dx++;
dx--;
add((i-1)*m+j,(dx-1)*m+dy,step);
dx=i,dy=j;
while(a[dx][dy]!='#') dy--;
dy++;
add((i-1)*m+j,(dx-1)*m+dy,step);
dx=i,dy=j;
while(a[dx][dy]!='#') dy++;
dy--;
add((i-1)*m+j,(dx-1)*m+dy,step);
}
}
}
spfa((b_x-1)*m+b_y);
if(d[(e_x-1)*m+e_y]>=99999999) cout<<"nemoguce";
else cout<<d[(e_x-1)*m+e_y];
return 0;
}