1. 程式人生 > >【BZOJ1967】[AHOI2005]穿越磁場(最短路)

【BZOJ1967】[AHOI2005]穿越磁場(最短路)

truct str next sort ems emp lower ont urn

【BZOJ1967】[AHOI2005]穿越磁場(最短路)

題面

BZOJ
洛谷

題解

一個顯然的思路是這樣的,我們的正方形的邊長把整個平面割成了若幹塊,顯然每個聯通塊都可以看著做一個點,那麽接下來只需要把所有的有相鄰邊的聯通塊全部連上一條長度為\(1\)的邊表示如果要從這個聯通塊到達另外一個聯通塊,需要穿過這一條邊,那麽最終的答案就變成了起點和終點所在聯通塊的最短路。因為找聯通塊不好搞,其實離散之後再當成網格圖做就好了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long
#define MAX 250
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
struct Matrix{int x1,x2,y1,y2;}p[MAX<<1];
int n,Sx[MAX<<3],Sy[MAX<<3],tx,ty;
int Bx,By,Ex,Ey;
bool visx[MAX<<1][MAX<<1],visy[MAX<<1][MAX<<1];
struct Line{int v,next,w;}e[MAX*MAX*10];
int h[MAX*MAX<<2],cnt=1;
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int d[4][2]={1,0,-1,0,0,1,0,-1};
int id(int x,int y){return x*ty+y-ty;}
int dis[MAX*MAX<<1];bool vis[MAX*MAX<<1];
void SPFA()
{
    queue<int> Q;Q.push(id(Bx,By));
    memset(dis,63,sizeof(dis));dis[id(Bx,By)]=0;
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        for(int i=h[u];i;i=e[i].next)
        {
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                if(!vis[v])vis[v]=true,Q.push(v);
            }
        }
        vis[u]=false;
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)
    {
        int x=read(),y=read(),c=read();
        p[i]=(Matrix){x,x+c,y+c,y};
    }
    Bx=read();By=read();Ex=read();Ey=read();
    Sx[++tx]=Bx;Sx[++tx]=Ex;Sy[++ty]=By;Sy[++ty]=Ey;
    for(int i=1;i<=n;++i)Sx[++tx]=p[i].x1,Sx[++tx]=p[i].x2;
    for(int i=1;i<=n;++i)Sy[++ty]=p[i].y1,Sy[++ty]=p[i].y2;
    sort(&Sx[1],&Sx[tx+1]);sort(&Sy[1],&Sy[ty+1]);
    tx=unique(&Sx[1],&Sx[tx+1])-Sx-1;ty=unique(&Sy[1],&Sy[ty+1])-Sy-1;
    for(int i=2;i<=tx;++i)if(Sx[i]-Sx[i-1]>1)Sx[++tx]=Sx[i]-1;
    for(int i=2;i<=ty;++i)if(Sy[i]-Sy[i-1]>1)Sy[++ty]=Sy[i]-1;
    Sx[++tx]=-10;Sy[++ty]=-10;Sx[++tx]=1e9;Sy[++ty]=1e9;
    sort(&Sx[1],&Sx[tx+1]);sort(&Sy[1],&Sy[ty+1]);
    tx=unique(&Sx[1],&Sx[tx+1])-Sx-1;ty=unique(&Sy[1],&Sy[ty+1])-Sy-1;
    for(int i=1;i<=n;++i)
    {
        p[i].x1=lower_bound(&Sx[1],&Sx[tx+1],p[i].x1)-Sx;
        p[i].x2=lower_bound(&Sx[1],&Sx[tx+1],p[i].x2)-Sx;
        p[i].y1=lower_bound(&Sy[1],&Sy[ty+1],p[i].y1)-Sy;
        p[i].y2=lower_bound(&Sy[1],&Sy[ty+1],p[i].y2)-Sy;
        for(int j=p[i].x1;j<=p[i].x2;++j)visx[j][p[i].y1-1]=visx[j][p[i].y2-1]=true;
        for(int j=p[i].y2;j<=p[i].y1;++j)visy[p[i].x1][j]=visy[p[i].x2][j]=true;
    }
    Bx=lower_bound(&Sx[1],&Sx[tx+1],Bx)-Sx;By=lower_bound(&Sy[1],&Sy[ty+1],By)-Sy;
    Ex=lower_bound(&Sx[1],&Sx[tx+1],Ex)-Sx;Ey=lower_bound(&Sy[1],&Sy[ty+1],Ey)-Sy;
    for(int i=1;i<=tx;++i)
        for(int j=1;j<=ty;++j)
            for(int k=0;k<4;++k)
            {
                int x=i+d[k][0],y=j+d[k][1];
                if(x<1||y<1||x>tx||y>ty)continue;
                if(k==0)Add(id(i,j),id(x,y),visy[x][y]);
                if(k==1)Add(id(i,j),id(x,y),visy[i][j]);
                if(k==2)Add(id(i,j),id(x,y),visx[i][j]);
                if(k==3)Add(id(i,j),id(x,y),visx[x][y]);
            }
    SPFA();
    printf("%d\n",dis[id(Ex,Ey)]);
    return 0;
}

【BZOJ1967】[AHOI2005]穿越磁場(最短路)