• [Ctsc2000]冰原探险


    Description

    传说中,南极有一片广阔的冰原,在冰原下藏有史前文明的遗址。整个冰原被横竖划分成了很多个大小相等的方格。在这个冰原上有N个大小不等的矩形冰山,这些巨大的冰山有着和南极一样古老的历史,每个矩形冰山至少占据一个方格,且其必定完整地占据方格。冰山和冰山之间不会重叠,也不会有边或点相连。以下两种情况均是不可能出现的:

    img

    ACM探险队在经过多年准备之后决定在这个冰原上寻找遗址。根据他们掌握的资料,在这个冰原上一个大小为一格的深洞中,藏有一个由史前人类制作的开关。而唯一可以打开这个开关的是一个占据接近一格的可移动的小冰块。显然,在南极是不可能有这样小的独立冰块的,所以这块冰块也一定是史前文明的产物。他们在想办法把这个冰块推到洞里去,这样就可以打开一条通往冰原底部的通道,发掘史前文明的秘密。冰块的起始位置与深洞的位置均不和任何冰山相邻。这个冰原上的冰面和冰山都是完全光滑的,轻轻的推动冰块就可以使这个冰块向前滑行,直到撞到一座冰山就在它的边上停下来。冰块可以穿过冰面上所有没有冰山的区域,也可以从两座冰山之间穿过(见下图)。冰块只能沿网格方向推动。

    img

    请你帮助他们以最少的推动次数将冰块推入深洞中。

    Input

    输入文件第一行为冰山的个数N (1<=N<=4000),第二行为冰块开始所在的方格坐标X1,Y1,第三行为深洞所在的方格坐标X2,Y2,以下N行每行有四个数,分别是每个冰山所占的格子左上角和右下角坐标Xi1,Yi1,Xi2,Yi2

    Output

    输出文件仅包含一个整数,为最少推动冰块的次数。如果无法将冰块推入深洞中,则输出0。

    Sample Input

    2
    1 1
    5 5
    1 3 3
    6 2 8

    Sample Output

    3

    HINT

    数据如下:JudgeOnline/upload/201604/2541.rar

    Solution

    看上去比较不容易出思路的一道题目。如果这个题坐标范围比较小的话,我们想想是不是可以搞一个bool矩阵直接暴力判断bfs。那么这个题就没有什么难度了。好了,上代码。 那么出题人就故意不写坐标范围,明摆着就是让你这么做然后挂掉的。

    那么我们就只能用结构体来保存坐标。经过仔细排查可以发现,我们从一个地方推冰块,那么它就一定要撞到一座冰山,嗯,那么我们就可以预处理出来从一条边能到达的边分别是哪些就可以了,然后从初始点上下左右试一试,最后出解。然后还有一个,从一个横着的边上只能左右推,从一个竖着的边上只能上下推。

    那就没什么其他的了,不过代码确实,不短。

    Code

    #include <iostream>
    #include <cmath>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #define re register
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int inf = 0x3f3f3f3f;
    int A,B,C,D,cnt;
    int tot,head[16005],nxt[50005],to[50005],n,num,vis[200001];
    int h[200001][2],front,tail;
    struct po{
    	int a,b,c,d,p[10];
    }s[4005];
    inline int read()
    {
    	int x=0,c=1;
    	char ch=' ';
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	while(ch=='-') c*=-1,ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return x*c;
    }
    inline int Up(int x,int y)
    {
    	int ans=0,maxx=-inf;
    	for(re int i=1;i<=n;i++){
    		int a=s[i].a,b=s[i].b,c=s[i].c,d=s[i].d;
    		if(c+1<=x&&y>=b&&y<=d&&maxx<c+1){
    			maxx=c+1;
    			ans=s[i].p[2];
    		}
    	}
    	if(y==D&&C<=x&&maxx<C) ans=cnt;
    	return ans;
    }
    inline int Down(int x,int y)
    {
    	int ans=0,minn=inf;
    	for(re int i=1;i<=n;i++){
    		int a=s[i].a,b=s[i].b,c=s[i].c,d=s[i].d;
    		if(a-1>=x&&y>=b&&y<=d&&minn>a-1){
    			minn=a-1;
    			ans=s[i].p[1];
    		}
    	}
    	if(y==D&&C>=x&&minn>C) ans=cnt;
    	return ans;
    }
    inline int Left(int x,int y)
    {
    	int ans=0,maxx=-inf;
    	for(re int i=1;i<=n;i++){
    		int a=s[i].a,b=s[i].b,c=s[i].c,d=s[i].d;
    		if(d+1<=y&&x>=a&&x<=c&&maxx<d+1){
    			maxx=d+1;ans=s[i].p[4];
    		}
    	}
    	if(x==C&&D<=y&&maxx<D) ans=cnt;
    	return ans;
    }
    inline int Right(int x,int y)
    {
    	int ans=0,minn=inf;
    	for(re int i=1;i<=n;i++){
    		int a=s[i].a,b=s[i].b,c=s[i].c,d=s[i].d;
    		if(b-1>=y&&x>=a&&x<=c&&minn>b-1){
    			minn=b-1;
    			ans=s[i].p[3];
    		}
    	}
    	if(x==C&&D>=y&&minn>D) ans=cnt;
    	return ans;
    }
    inline void add(int from,int too)
    {
    	nxt[++num]=head[from];
    	to[num]=too;
    	head[from]=num;
    }
    inline int bfs()
    {
    	front=0;tail=1;
    	h[tail][1]=1;
    	h[tail][2]=0;
    	while(front<=tail){
    		int now=h[++front][1],dep=h[front][2];
    		for(re int i=head[now];i;i=nxt[i]){
    			int v=to[i];
    			if(v==cnt) return dep+1;
    			if(!vis[v]){
    				vis[v]=1;
    				h[++tail][1]=v;
    				h[tail][2]=dep+1;
    			}
    		}
    	}
    	return 0;
    }
    int main() 
    {
        n=read();
        A=read();B=read();C=read();D=read();
        for(re int i=1;i<=n;i++){
        	s[i].a=read();s[i].b=read();s[i].c=read();s[i].d=read();
        }
        cnt=1;
        for(re int i=1;i<=n;i++)
        	for(re int j=1;j<=4;j++) s[i].p[j]=++cnt;
        ++cnt;
    	int x;
    	x=Up(A,B); if(x) add(1,x);
    	x=Down(A,B); if(x) add(1,x);
    	x=Left(A,B); if(x) add(1,x);
    	x=Right(A,B); if(x) add(1,x);
    	for(re int i=1;i<=n;i++){
    		int a=s[i].a,b=s[i].b,c=s[i].c,d=s[i].d;
    		int x;
    		x=Up(a,b-1); if(x) add(s[i].p[3],x);
    		x=Up(a,d+1); if(x) add(s[i].p[4],x);
    		x=Down(c,b-1); if(x) add(s[i].p[3],x);
    		x=Down(c,d+1); if(x) add(s[i].p[4],x);
    		x=Left(a-1,b); if(x) add(s[i].p[1],x);
    		x=Left(c+1,b); if(x) add(s[i].p[2],x);
    		x=Right(a-1,d); if(x) add(s[i].p[1],x);
    		x=Right(c+1,d); if(x) add(s[i].p[2],x);
    	}
    	cout<<bfs();
        return 0;
    }
    
    
  • 相关阅读:
    PHP中的trait
    Laravel中的队列
    微信小程序开发常见问题
    python学习day1
    javaScript实现栈的创建,添加元素,检查栈是否为空,删除元素,查看栈顶元素,清空栈元素,toString方法,通过栈实现多种进制转换
    join&concat&splice&slice&indexOf&lastindexOf&charCodeAt&fromCharCode
    使用函数自动创建表格
    两种方式实现随机颜色
    多选全选框使用addEvenListener实现
    使用setInterval来控制正方形的移动的频率(每隔1秒),鼠标点击停止移动,当再次点击恢复移动
  • 原文地址:https://www.cnblogs.com/victorique/p/9021260.html
Copyright © 2020-2023  润新知