JZOJ5381. 【NOIP2017提高A组模拟9.21】传送蛋糕

这里写图片描述

题解

这里面的传送门是比较特殊的,
我们可以发现,传送门的实质就是:
在某个点(x,y)到它四周的墙的距离都为它到四面墙的最短距离。

那么我们就可以连边,
每个点向外连8条边。
然而,边数是十分巨大的,并不能全部记录下来。

我们可以O(nm)预处理出来每个点,往四周走,
碰到的第一面墙,利用这个可以快速地求出这个点向外连的8条边。

还有一个优化,就是在spfa中的队列,
要从dis小的开始枚举,这样每个点的进队次数就不会超过8。

code

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 2333
#define db double
#define P putchar
#define G getchar
#define mo 1004535809
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}

void write(int x)
{
     if(x>9) write(x/10);
     P(x%10+'0');
}

struct node
{
    int x,dis;
}t,now;

bool operator <(node a,node b)
{
    return a.dis>b.dis;
}

priority_queue <node> q;

int f[N][N][4],n,m,dis[N*N],stx,sty,fix,fiy,mi,p,x,y,to,v;
//int nxt[N*N*8],to[N*N*8],v[N*N*8],b[N*N],tot;
bool bz[N*N];
char a[N][N];

int get(int x,int y)
{
    return x*(m+2)+y;
}

//void ins(int x,int y,int z){nxt[++tot]=b[x];to[tot]=y;v[tot]=z;b[x]=tot;}

int main()
{
    freopen("portals.in","r",stdin);
    freopen("portals.out","w",stdout);
    read(n);read(m);ch='-';
    for(int i=1;i<=n;i++)
    {
        a[i][0]=a[i][m+1]='#';  
        while(ch!='S' && ch!='.' && ch!='#' && ch!='C')ch=getchar();
        for(int j=1;j<=m;j++)
        {
            if(ch=='S')stx=i,sty=j;
            if(ch=='C')fix=i,fiy=j;
            a[i][j]=ch,ch=getchar();
        }
    }

    for(int i=0;i<=m+1;i++)
        a[0][i]=a[n+1][i]='#';

    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=m+1;j++)
            if(a[i][j]!='#')
                f[i][j][0]=f[i-1][j][0]+1,f[i][j][3]=f[i][j-1][3]+1;

    for(int i=n+1;i>=0;i--)
        for(int j=m+1;j>=0;j--)
            if(a[i][j]!='#')
                f[i][j][2]=f[i+1][j][2]+1,f[i][j][1]=f[i][j+1][1]+1;

    /*for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]=='#')continue;
            p=get(i,j);
            ins(p,get(i+1,j),1);
            ins(p,get(i-1,j),1);
            ins(p,get(i,j+1),1);
            ins(p,get(i,j-1),1);
            mi=min(min(f[i][j][0],f[i][j][1]),min(f[i][j][2],f[i][j][3]));
            ins(p,get(i-f[i][j][0]+1,j),mi);
            ins(p,get(i+f[i][j][2]-1,j),mi);
            ins(p,get(i,j+f[i][j][1]-1),mi);
            ins(p,get(i,j-f[i][j][3]+1),mi);
        }*/

    /*for(int i=0;i<=n+1;i++)
    {
        for(int j=0;j<=m+1;j++)
        {
            write(f[i][j][0]),P(' ');
            write(f[i][j][1]),P(' ');
            write(f[i][j][2]),P(' ');
            write(f[i][j][3]),P('\n');
            write(min(min(f[i][j][0],f[i][j][1]),min(f[i][j][2],f[i][j][3]))),P(' ');
        }
        P('\n');
    }*/

    memset(dis,127,sizeof(dis));
    memset(bz,0,sizeof(bz));
    dis[t.x=get(stx,sty)]=0;
    t.dis=0;bz[t.x]=1;
    q.push(t);

    while(!q.empty())
    {
        now=q.top();q.pop();
        p=now.x;
        x=p/(m+2);y=p%(m+2);
        //write(now.dis),P('\n');
        //write(x),P(' '),write(y),P('\n');
        if(a[x][y]=='#')continue;
        v=1;
        to=get(x+1,y);
        if(dis[to]>dis[p]+v){dis[to]=dis[p]+v;if(!bz[to]){bz[to]=1;t.x=to;t.dis=dis[to];q.push(t);}}
        to=get(x-1,y);
        if(dis[to]>dis[p]+v){dis[to]=dis[p]+v;if(!bz[to]){bz[to]=1;t.x=to;t.dis=dis[to];q.push(t);}}
        to=get(x,y+1);
        if(dis[to]>dis[p]+v){dis[to]=dis[p]+v;if(!bz[to]){bz[to]=1;t.x=to;t.dis=dis[to];q.push(t);}}
        to=get(x,y-1);
        if(dis[to]>dis[p]+v){dis[to]=dis[p]+v;if(!bz[to]){bz[to]=1;t.x=to;t.dis=dis[to];q.push(t);}}

        v=min(min(f[x][y][0],f[x][y][1]),min(f[x][y][2],f[x][y][3]));

        to=get(x-f[x][y][0]+1,y);
        if(dis[to]>dis[p]+v){dis[to]=dis[p]+v;if(!bz[to]){bz[to]=1;t.x=to;t.dis=dis[to];q.push(t);}}
        to=get(x+f[x][y][2]-1,y);
        if(dis[to]>dis[p]+v){dis[to]=dis[p]+v;if(!bz[to]){bz[to]=1;t.x=to;t.dis=dis[to];q.push(t);}}
        to=get(x,y+f[x][y][1]-1);
        if(dis[to]>dis[p]+v){dis[to]=dis[p]+v;if(!bz[to]){bz[to]=1;t.x=to;t.dis=dis[to];q.push(t);}}
        to=get(x,y-f[x][y][3]+1);
        if(dis[to]>dis[p]+v){dis[to]=dis[p]+v;if(!bz[to]){bz[to]=1;t.x=to;t.dis=dis[to];q.push(t);}}

        /*
        for(int i=b[p];i;i=next[i])
            if(dis[to[i]]>dis[p]+v[i])
            {
                dis[to[i]]=dis[p]+v[i];
                if(!bz[to[i]])
                {
                    bz[to[i]]=1;
                    t.x=to[i];t.dis=dis[to[i]];
                    q.push(t);
                }
            }*/
        bz[p]=0;
    }
    write(dis[get(fix,fiy)]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值