构图(+BFS)——BZOJ2541/Luogu3716 [CTSC2000]冰原探险

来源:互联网 发布:网络传播正能量的例子 编辑:程序博客网 时间:2024/04/29 21:25

题面:Luogu3716 BZOJ2541
无限烧脑预处理建图系列,同时也是我攻下的CTSC第一题!
只要把图能建得出来就Accepted了
所以只说建图(最后的bfs有什么好说的。。。
我们把冰山拆成四个点,冰山的每一边是一个点
然后我们暴力对每一个点(也就是冰山的边)往上下左右找最近的能撞的冰山(或者直接掉进洞里),然后连上有向边(注意有向边!!!)
当然啦,每一条边要么上下方向要么左右方向
起点再特殊处理一下好了
但是呢你建的时候还有很多要处理的东西
比如几个坑点:

  • 洞必须要特判!(下面会说)
  • 数据中坐标可能是负数(数据里好像有)
  • 数据中坐标可能爆int(这个我不太确定但是可能吧)
  • (以上两点是针对于题中未给坐标范围所致)
  • 选择上下左右建图时必须要滑过整块冰山的边(因为有可能洞在冰山的边上如果直接滑出去就会忽略洞导致输出0)
  • 对于上一点具体意思就是说往上下左右找的时候要从这条边的起始点出发而不是终点
  • 还有撞到冰山坐标还要减1或加1(这个好像忽略应该也没关系,我也不知道),然而洞就不需要

最后跑bfs,完结,撒花!
献上原来压到只剩70行的100行代码(码力啊码力)

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<iostream>#include<cstdlib>#include<set>#include<map>#include<string>#include<ctime>#include<queue>#include<vector>using namespace std;typedef long long ll;bool vis[100001];struct ppap{ll xx,xy,dx,dy;}a[100001];int dist[100001],bh[5001][5];int nedge=0,p[100001],nex[100001],head[100001];int n,s=1,cnt=1,t;ll sx,sy,tx,ty;inline void addedge(int a,int b){p[++nedge]=b;nex[nedge]=head[a];head[a]=nedge;}inline void add(int x,int y,int z){if(y<t)addedge(x,bh[y][z]);else addedge(x,t);}inline int down(ll x,ll y){    int fh=0;ll min=1e18;    for(int i=1;i<=n;i++)        if(y>=a[i].xy&&y<=a[i].dy&&x<=a[i].xx-1&&min>a[i].xx-1)            min=a[i].xx-1,fh=i;    if(y==ty&&x<=tx&&min>tx)return t;    return fh;}inline int left(ll x,ll y){    int fh=0;ll max=-1e18;    for(int i=1;i<=n;i++)        if(x>=a[i].xx&&x<=a[i].dx&&y>=a[i].dy+1&&max<a[i].dy+1)            max=a[i].dy+1,fh=i;    if(x==tx&&y>=ty&&max<ty)return t;    return fh;}inline int up(ll x,ll y){    int fh=0;ll max=-1e18;    for(int i=1;i<=n;i++)        if(y>=a[i].xy&&y<=a[i].dy&&x>=a[i].dx+1&&max<a[i].dx+1)            max=a[i].dx+1,fh=i;    if(y==ty&&x>=tx&&max<tx)return t;    return fh;}inline int right(ll x,ll y){    int fh=0;ll min=1e18;    for(int i=1;i<=n;i++)        if(x>=a[i].xx&&x<=a[i].dx&&y<=a[i].xy-1&&min>a[i].xy-1)            min=a[i].xy-1,fh=i;    if(x==tx&&y<=ty&&min>ty)return t;    return fh;}inline void bfs(int x){    dist[t]=1e9;dist[x]=0;queue<int>q;q.push(x);vis[x]=1;    while(!q.empty()){        int now=q.front();q.pop();        for(int k=head[now];k;k=nex[k])if(!vis[p[k]]){            dist[p[k]]=dist[now]+1;            if(p[k]==t)return;vis[p[k]]=1;            q.push(p[k]);        }    }}int main(){    scanf("%d%lld%lld%lld%lld",&n,&sx,&sy,&tx,&ty);    for(int i=1;i<=n;i++)        scanf("%lld%lld%lld%lld",&a[i].xx,&a[i].xy,&a[i].dx,&a[i].dy);    for(int i=1;i<=n;i++)        for(int j=1;j<5;j++)bh[i][j]=++cnt;t=++cnt;    if(cnt=down(sx,sy))        add(s,cnt,1);    if(cnt=left(sx,sy))        add(s,cnt,2);    if(cnt=up(sx,sy))        add(s,cnt,3);    if(cnt=right(sx,sy))        add(s,cnt,4);    for(int i=1;i<=n;i++){        if(cnt=down(a[i].xx,a[i].dy+1))            add(bh[i][2],cnt,1);        if(cnt=down(a[i].xx,a[i].xy-1))            add(bh[i][4],cnt,1);        if(cnt=left(a[i].xx-1,a[i].dy))            add(bh[i][1],cnt,2);        if(cnt=left(a[i].dx+1,a[i].dy))            add(bh[i][3],cnt,2);        if(cnt=up(a[i].dx,a[i].dy+1))            add(bh[i][2],cnt,3);        if(cnt=up(a[i].dx,a[i].xy-1))            add(bh[i][4],cnt,3);        if(cnt=right(a[i].xx-1,a[i].xy))            add(bh[i][1],cnt,4);        if(cnt=right(a[i].dx+1,a[i].xy))            add(bh[i][3],cnt,4);    }    bfs(1);    if(dist[t]!=1e9)printf("%d",dist[t]);    else puts("0");    return 0;}