jzoj5781 秘密通道
程序员文章站
2022-06-12 13:38:13
...
题目点这里(需要jzoj账号)
- 首先我们看到这道题,这道题的基本是走迷宫,我们都做过类似的题,这道题只是在此基础上多了一个可以传送的条件
- 我们这样去想,对于一个点,它可以往上下左右四个方向射出子弹,然后打出相应的传送门出口,利用这些出口我们需要走到距离当前点最近的一堵墙,然后再花1的时间传送对吧?那么我们可以首先预处理出每个点距离最近墙的距离,然后判断它到四个方向的出口是否需要传送,然后不断搜索,最后搜索出答案,若是最后的F
点未被修改过,那么我们就输出nemoguce
。
- 下面是代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int next[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
struct node{
char data;
int step;
int towall;
}a[505][505];
struct wall{
int x,y;
};
int n,m;
int xs,ys,xe,ye;
inline void Search1(int nowx1,int nowy1,int nowstep){
if(a[nowx1][nowy1].data=='#') return;
a[nowx1][nowy1].step=nowstep;
int Tox=nowx1,Toy=nowy1;
while(a[Tox-1][Toy].data!='#') Tox--;
if(nowstep+a[nowx1][nowy1].towall<a[Tox][Toy].step)
Search1(Tox,Toy,nowstep+a[nowx1][nowy1].towall);
Tox=nowx1;
while(a[Tox+1][Toy].data!='#') Tox++;
if(nowstep+a[nowx1][nowy1].towall<a[Tox][Toy].step)
Search1(Tox,Toy,nowstep+a[nowx1][nowy1].towall);
Tox=nowx1;
while(a[Tox][Toy-1].data!='#') Toy--;
if(nowstep+a[nowx1][nowy1].towall<a[Tox][Toy].step)
Search1(Tox,Toy,nowstep+a[nowx1][nowy1].towall);
Toy=nowy1;
while(a[Tox][Toy+1].data!='#') Toy++;
if(nowstep+a[nowx1][nowy1].towall<a[Tox][Toy].step)
Search1(Tox,Toy,nowstep+a[nowx1][nowy1].towall);
for(int i=0;i<4;i++){
if(a[nowx1+next[i][0]][nowy1+next[i][1]].step>nowstep+1)
Search1(nowx1+next[i][0],nowy1+next[i][1],nowstep+1);
}
return;
}
void Search2(int nowx,int nowy){
int dis=1;
int Gox,Goy;
while(1){
for(register int i=0;i<=dis;i++){
Gox=i;
Goy=dis-i;
if(a[nowx-Gox][nowy-Goy].data=='#'){a[nowx][nowy].towall=dis;return;}
if(a[nowx-Gox][nowy+Goy].data=='#'){a[nowx][nowy].towall=dis;return;}
if(a[nowx+Gox][nowy-Goy].data=='#'){a[nowx][nowy].towall=dis;return;}
if(a[nowx+Gox][nowy+Goy].data=='#'){a[nowx][nowy].towall=dis;return;}
}
dis++;
}
return;
}
int main()
{
// freopen("portal.in","r",stdin);
// freopen("portal.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>a[i][j].data;
if(a[i][j].data=='C') xs=i,ys=j;
if(a[i][j].data=='F') xe=i,ye=j;
a[i][j].step=99999999;
a[i][j].towall=99999999;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j].data!='#')
Search2(i,j);
Search1(xs,ys,0);
if(a[xe][ye].step==99999999) printf("nemoguce");
else printf("%d",a[xe][ye].step);
return 0;
}
- 你若是看到了这里,那么你或许会发现,我们预想的AC并没有出现,而是出现了新的问题TLE,这是因为我们不断地搜索毫无章法,导致了我们无法去除掉无效的搜索,从而导致了我们时间上的浪费。
- 那么我们可以考虑其它方式,仔细分析我们可以发现,我们可以将我们搜索的部分删去,在我们预处理时我们将当前点指向上下左右四个方向的第一个方块和最后一块(利用墙体优化后)全部连上一条边,最后用spfa跑一遍最短路是不是就可以了?
- 下面是代码:
#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)); //spfa找寻最短路
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 much(int nowx,int nowy){ //找距离最近墙的距离
int dis=1;
int Gox,Goy;
while(1){
for(register int i=0;i<=dis;i++){
Gox=i;
Goy=dis-i;
if(a[nowx-Gox][nowy-Goy]=='#'){return dis;}
if(a[nowx-Gox][nowy+Goy]=='#'){return dis;}
if(a[nowx+Gox][nowy-Goy]=='#'){return dis;}
if(a[nowx+Gox][nowy+Goy]=='#'){return dis;}
}
dis++;
}
}
int main(){
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;
}