【bzoj 2541】 [Ctsc2000]冰原探险(BFS)
2541: [Ctsc2000]冰原探险
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 39 Solved: 25
[Submit][Status][Discuss]
Description
传说中,南极有一片广阔的冰原,在冰原下藏有史前文明的遗址。整个冰原被横竖划分成了很多个大小相等的方格。在这个冰原上有N个大小不等的矩形冰山,这些巨大的冰山有着和南极一样古老的历史,每个矩形冰山至少占据一个方格,且其必定完整地占据方格。冰山和冰山之间不会重叠,也不会有边或点相连。以下两种情况均是不可能出现的:
ACM探险队在经过多年准备之后决定在这个冰原上寻找遗址。根据他们掌握的资料,在这个冰原上一个大小为一格的深洞中,藏有一个由史前人类制作的开关。而唯一可以打开这个开关的是一个占据接近一格的可移动的小冰块。显然,在南极是不可能有这样小的独立冰块的,所以这块冰块也一定是史前文明的产物。他们在想办法把这个冰块推到洞里去,这样就可以打开一条通往冰原底部的通道,发掘史前文明的秘密。冰块的起始位置与深洞的位置均不和任何冰山相邻。这个冰原上的冰面和冰山都是完全光滑的,轻轻的推动冰块就可以使这个冰块向前滑行,直到撞到一座冰山就在它的边上停下来。冰块可以穿过冰面上所有没有冰山的区域,也可以从两座冰山之间穿过(见下图)。冰块只能沿网格方向推动。
请你帮助他们以最少的推动次数将冰块推入深洞中。
Input
输入文件第一行为冰山的个数N (1<=N<=4000),第二行为冰块开始所在的方格坐标X1,Y1,第三行为深洞所在的方格坐标X2,Y2,以下N行每行有四个数,分别是每个冰山所占的格子左上角和右下角坐标Xi1,Yi1,Xi2,Yi2
Output
输出文件仅包含一个整数,为最少推动冰块的次数。如果无法将冰块推入深洞中,则输出0。
Sample Input
1 1
5 5
1 3 3 3
6 2 8
Sample Output
HINT
Source
【题解】【BFS】
【算法简单,但乍一看没什么思路。就算是想到BFS也是很暴力的直接BFS】
【实际这道题,因为整个网格没有边界,所以不能直接暴力。由于每一次推小冰块只有在打到冰山才停止。我们可以预处理若冰块打到当前冰山的当前面,下一次可能再打到哪一冰山的哪一面。】
【so,我们把每一冰山的每一面作为一个点,由当前点向可能转移到的点连有向边,并把最开始的小冰块和深洞也作为一个点】
【预处理后,跑BFS最短路】
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
struct node{
ll up,down,left,right;
int num[5];
}ice[4010];
queue<int>que;
int a[200010],nxt[200010],p[200010],tot;
ll xi,yi,xt,yt;
int n,cnt,dis[200010];
bool vis[200010];
int tmp(node a,node b)
{
if(a.down<b.down) return 1;
if(a.down>b.down) return 0;
if(a.left<b.left) return 1;
return 0;
}
inline void add(int x,int y)
{
tot++; a[tot]=y; nxt[tot]=p[x]; p[x]=tot;
}
inline int find_up(ll x,ll y,int opt)
{
int ans=-1,low=-1;
for(int i=1;i<=n;++i)
if(i!=opt)
if(ice[i].left<=x&&ice[i].right>=x&&ice[i].down>=y)
if(low==-1||low>ice[i].down) low=ice[i].down,ans=ice[i].num[1];
if(x==xt&&y<=yt&&(low>=yt||low==-1)) return cnt;
return ans;
}
inline int find_down(ll x,ll y,int opt)
{
int ans=-1,high=-1;
for(int i=1;i<=n;++i)
if(opt!=i)
if(ice[i].left<=x&&ice[i].right>=x&&ice[i].up<=y)
if(high==-1||high<ice[i].up) high=ice[i].up,ans=ice[i].num[2];
if(x==xt&&y>=yt&&(high<=yt||high==-1)) return cnt;
return ans;
}
inline int find_left(ll x,ll y,int opt)
{
int ans=-1,lmax=-1;
for(int i=1;i<=n;++i)
if(opt!=i)
if(ice[i].up>=y&&ice[i].down<=y&&ice[i].right<=x)
if(lmax==-1||lmax<ice[i].right) lmax=ice[i].right,ans=ice[i].num[4];
if(y==yt&&x>=xt&&(lmax<=xt||lmax==-1)) return cnt;
return ans;
}
inline int find_right(ll x,ll y,int opt)
{
int ans=-1,rmin=-1;
for(int i=1;i<=n;++i)
if(opt!=i)
if(ice[i].up>=y&&ice[i].down<=y&&ice[i].left>=x)
if(rmin==-1||rmin>ice[i].left) rmin=ice[i].left,ans=ice[i].num[3];
if(y==yt&&x<=xt&&(rmin>=xt||rmin==-1)) return cnt;
return ans;
}
inline void bfs()
{
int inf;
memset(dis,127/3,sizeof(dis));
que.push(1); vis[1]=1; dis[1]=0; inf=dis[0];
while(!que.empty())
{
int u=que.front(); que.pop();
if(u==cnt) break;
for(int i=p[u];i!=-1;i=nxt[i])
if(dis[a[i]]>dis[u]+1)
{
dis[a[i]]=dis[u]+1;
if(!vis[a[i]]) que.push(a[i]),vis[a[i]]=1;
}
}
if(dis[cnt]==inf) printf("0\n");
else printf("%d\n",dis[cnt]);
return;
}
int main()
{
// freopen("ice.in","r",stdin);
// freopen("ice.out","w",stdout);
int i,j;
memset(p,-1,sizeof(p));
memset(nxt,-1,sizeof(nxt));
scanf("%d",&n);
scanf("%lld%lld%lld%lld\n",&xi,&yi,&xt,&yt);
for(i=1;i<=n;++i) scanf("%lld%lld%lld%lld",&ice[i].left,&ice[i].down,&ice[i].right,&ice[i].up);
sort(ice+1,ice+n+1,tmp);cnt=1;
for(i=1;i<=n;++i)
for(j=1;j<=4;++j)
ice[i].num[j]=++cnt;
int nm; cnt++;
nm=find_up(xi,yi,0); if(nm!=-1) add(1,nm);
nm=find_down(xi,yi,0); if(nm!=-1) add(1,nm);
nm=find_left(xi,yi,0); if(nm!=-1) add(1,nm);
nm=find_right(xi,yi,0); if(nm!=-1) add(1,nm);
for(i=1;i<=n;++i)
{
int l=ice[i].left,r=ice[i].right,u=ice[i].up,d=ice[i].down;
nm=find_up(l-1,d,i); if(nm!=-1) add(ice[i].num[3],nm);
nm=find_up(r+1,d,i); if(nm!=-1) add(ice[i].num[4],nm);
nm=find_down(l-1,u,i); if(nm!=-1) add(ice[i].num[3],nm);
nm=find_down(r+1,u,i); if(nm!=-1) add(ice[i].num[4],nm);
nm=find_left(r,u+1,i); if(nm!=-1) add(ice[i].num[2],nm);
nm=find_left(r,d-1,i); if(nm!=-1) add(ice[i].num[1],nm);
nm=find_right(l,u+1,i); if(nm!=-1) add(ice[i].num[2],nm);
nm=find_right(l,d-1,i); if(nm!=-1) add(ice[i].num[1],nm);
}
bfs();
return 0;
}
[大模拟练码力...]