zoukankan      html  css  js  c++  java
  • bzoj3919: [Baltic2014]portals

    Description

    给出一张四连通的网格图,'#'代表墙,'.'代表空地,'S'代表出发点,'C'代表目的地,地图四周都是墙,求S到C的最短路。
    走的时候可以向上下左右中的某个方向发射奇怪的东西(portals),portals会贴在发射方向的墙上。
    地图上只允许同时存在两个portals,如果已经发射了两个再发射第三个,那么你需要在之前的那两个中的选一个使它消失。
    两个portals可以存在于一块墙的两面,但不能存在于一块墙的同面。
    当你身边是墙且那块墙上有面向你的portals时,你可以走进那个portals,从另一个portals出来。
    相邻两点距离为1,走portals距离也为1

    Input

    第一行2个数R,C,表示矩形的长和宽
    接下来R行,每行一个长为C的字符串,表示这张图

    Output

    输出一行表示答案

    显然同个位置的传送门不会被用两次。由于传送门要走到才能传送且放置不花时间,可以认为入口传送门在进入的一瞬间才放置。当前在某个方格时,出口传送门有4个位置可以放置,而入口传送门则贪心地走到最近的墙边放置。预处理每个方格4个方向放置传送门的位置和到墙的最近距离,然后就可以用dijkstra算法求最短路,由于最短路长度不超过nm,可以用桶代替堆优化最短路,总复杂度O(nm),达到理论最优。

    #include<cstdio>
    int n,m,sx,sy,tx,ty;
    int q[1100007][2],ql=0,qr=0;
    char s[1007][1007];
    int l1[1007][1007],l2[1007][1007];
    int xd[]={-1,0,1,0},yd[]={0,-1,0,1};
    int us[1007][1007];
    int ds[1007][1007];
    int ls[1007][1007];
    int rs[1007][1007];
    int es[5100007],enx[5100007],e0[1000007],ep=2,now=0;
    void push(int x,int y,int z){
        if(l2[x][y]<=z)return;
        l2[x][y]=z;
        es[ep]=x<<10|y;enx[ep]=e0[z];e0[z]=ep++;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i){
            scanf("%s",s[i]+1);
            for(int j=1;j<=m;++j){
                if(s[i][j]=='S')sx=i,sy=j,s[i][j]='.';
                if(s[i][j]=='C')tx=i,ty=j,s[i][j]='.';
            }
        }
        for(int i=0;i<=n+1;++i){
            for(int j=0;j<=m+1;++j)if(s[i][j]!='.'){
                q[qr][0]=i;q[qr++][1]=j;
            }else l1[i][j]=l2[i][j]=n*m;
        }
        while(ql!=qr){
            int x=q[ql][0],y=q[ql++][1];
            for(int d=0;d<4;++d){
                int x1=x+xd[d],y1=y+yd[d];
                if(x1<1||x1>n||y1<1||y1>m)continue;
                if(s[x1][y1]=='.'&&l1[x1][y1]>l1[x][y]+1){
                    l1[x1][y1]=l1[x][y]+1;
                    q[qr][0]=x1;q[qr++][1]=y1;
                }
            }
        }
        for(int i=0;i<=n+1;++i){
            for(int j=0;j<=m+1;++j)if(s[i][j]!='.'){
                if(s[i-1][j]=='.')for(int k=i-1;s[k][j]=='.';--k)ds[k][j]=i-1;
                if(s[i+1][j]=='.')for(int k=i+1;s[k][j]=='.';++k)us[k][j]=i+1;
                if(s[i][j-1]=='.')for(int k=j-1;s[i][k]=='.';--k)rs[i][k]=j-1;
                if(s[i][j+1]=='.')for(int k=j+1;s[i][k]=='.';++k)ls[i][k]=j+1;
            }
        }
        push(sx,sy,0);
        while(1){
            for(;!e0[now];++now);
            for(int i=e0[now];i;i=enx[i]){
                int x=es[i]>>10,y=es[i]&1023;
                if(l2[x][y]!=now)continue;
                if(x==tx&&y==ty)return printf("%d",l2[x][y]),0;
                for(int d=0;d<4;++d){
                    int x1=x+xd[d],y1=y+yd[d];
                    if(x1<1||x1>n||y1<1||y1>m)continue;
                    if(s[x1][y1]=='.')push(x1,y1,l2[x][y]+1);
                }
                if(us[x][y])push(us[x][y],y,l2[x][y]+l1[x][y]);
                if(ds[x][y])push(ds[x][y],y,l2[x][y]+l1[x][y]);
                if(ls[x][y])push(x,ls[x][y],l2[x][y]+l1[x][y]);
                if(rs[x][y])push(x,rs[x][y],l2[x][y]+l1[x][y]);
            }
            ++now;
        }
        return 0;
    }
  • 相关阅读:
    Android代码执行adb shell top命令读取结果
    Android8.0+跨应用发送广播和跨应用启动前台服务
    Android代码执行adb shell命令
    关于参数获取的那些事儿
    c# 如何处理自定义消息
    esp32 mqtt协议上报 dht11温湿度数据到onenet 指令下发控制开关灯
    swoole-simps自搭mqtt服务器,完美实现订阅,发布并存到mysql
    stm32f103c8t6+esp8266+dht11 mqtt上传温湿度到阿里云
    使用ST-Link下载程序出现Error:Flash Download Failed-“Cortex-M3“ 解决详细步骤(附图)
    stm32f407 oled iic例程,成功点亮oled屏
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6164307.html
Copyright © 2011-2022 走看看