最短路+离散化——BZOJ1967/Luogu2537 [AHOI2005]CROSS 穿越磁场

题面:BZOJ1967 Luogu2537
考虑到坐标范围非常大,但是矩阵数目很少
所以考虑离散化(离散化这个过程真的恶心
离散化的时候要注意把矩形的边左右或者上下都给留下来,这样才能给机器人跑路
离散化之后呢跑一遍spfa,注意边界处理
就是说不能连续在一条边界上面走
至于两个矩形的边交叉处不必担心,因为往交叉处走的话必定不是最优的
最后输出终点的最短路径即可

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<climits>
#include<string>
using namespace std;
const int dx[5]={0,1,-1,0,0};
const int dy[5]={0,0,0,1,-1};
struct ppap{int x,y;};
queue<ppap>q;
int sx,sy,zx,zy;
int n,x[1001],y[1001],c[1001],nn,mm;
int aa[1000005]={0},bb[1000005]={0};
int disx[10001],disy[10001],dist[301][301];
bool vis[301][301];int b[301][301];
int ans=0;
inline int read(){
    int k=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
    return k*f;
}
inline int spfa(int sx,int sy){
    for(int i=1;i<=nn;i++)
        for(int j=1;j<=mm;j++)dist[i][j]=1e9;
    memset(vis,0,sizeof vis);
    dist[sx][sy]=0;ppap rp;rp.x=sx;rp.y=sy;q.push(rp);
    while(!q.empty()){
        ppap now=q.front();q.pop();
        int xx=now.x,yy=now.y;
        for(int i=1;i<=4;i++){
            int p,nx=xx+dx[i],ny=yy+dy[i];
            if(!b[nx][ny])p=0;
            else if(b[nx][ny]==b[xx][yy])continue;
            else p=1;
            if(dist[nx][ny]>dist[xx][yy]+p){
                dist[nx][ny]=dist[xx][yy]+p;
                if(!vis[nx][ny]){
                    ppap pr;pr.x=nx;pr.y=ny;q.push(pr);
                    vis[nx][ny]=1;
                }
            }
        }
        vis[xx][yy]=0;
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++){
        x[i]=read();y[i]=read();c[i]=read();
        aa[x[i]+1]=aa[x[i]]=aa[x[i]-1]=1;
        bb[y[i]]=bb[y[i]-1]=bb[y[i]+1]=1;
        aa[x[i]+c[i]+1]=aa[x[i]+c[i]]=aa[x[i]+c[i]-1]=1;
        bb[y[i]+c[i]+1]=bb[y[i]+c[i]]=bb[y[i]+c[i]-1]=1;
    }
    sx=read();sy=read();zx=read();zy=read();
    aa[sx]=aa[zx]=1;bb[sy]=bb[zy]=1;
    int p=0,q=0;
    for(int i=0;i<=1000001;i++)if(aa[i]){
        q++;aa[i]=q;if(q>1)disx[q]=i-p;
        p=i;
    }
    nn=q;p=q=0;
    for(int i=0;i<=1000001;i++)if(bb[i]){
        q++;bb[i]=q;if(q>1)disy[q]=i-p;
        p=i;
    }
    mm=q;
    sx=aa[sx];sy=bb[sy];zx=aa[zx];zy=bb[zy];
    for(int i=1;i<=n;i++){
        int xx=x[i],dx=x[i]+c[i],xy=y[i],dy=y[i]+c[i];
        xx=aa[xx];xy=bb[xy];dx=aa[dx];dy=bb[dy];
        for(int j=xx;j<=dx;j++)b[j][xy]=b[j][dy]=i;
        for(int j=xy;j<=dy;j++)b[xx][j]=b[dx][j]=i;
    }//离散化
    spfa(sx,sy);
    printf("%d",dist[zx][zy]);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值