jzoj5781 秘密通道

这里写图片描述
这里写图片描述
这里写图片描述
题目点这里(需要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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值