CTSC2000 冰原探险
来源:互联网 发布:jira软件下载 编辑:程序博客网 时间:2024/04/29 07:27
这是我第一次写博客,写的不好,请多见谅~
今天上午日常考试,第二题就是这个题目。
传送门
(其实我是在vijos上测评的)
题目描述 :
传说中,南极有一片广阔的冰原,在冰原下藏有史前文明的遗址。整个冰原被横竖划分成了很多个大小相等的方格。在这个冰原上有N个大小不等的矩形冰山,这些巨大的冰山有着和南极一样古老的历史,每个矩形冰山至少占据一个方格,且其必定完整地占据方格。冰山和冰山之间不会重叠,也不会有边或点相连。以下两种情况均是不可能出现的:
ACM探险队在经过多年准备之后决定在这个冰原上寻找遗址。根据他们掌握的资料,在这个冰原上一个大小为一格的深洞中,藏有一个由史前人类制作的开关。而唯一可以打开这个开关的是一个占据接近一格的可移动的小冰块。显然,在南极是不可能有这样小的独立冰块的,所以这块冰块也一定是史前文明的产物。他们在想办法把这个冰块推到洞里去,这样就可以打开一条通往冰原底部的通道,发掘史前文明的秘密。冰块的起始位置与深洞的位置均不和任何冰山相邻。这个冰原上的冰面和冰山都是完全光滑的,轻轻的推动冰块就可以使这个冰块向前滑行,直到撞到一座冰山就在它的边上停下来。冰块可以穿过冰面上所有没有冰山的区域,也可以从两座冰山之间穿过(见下图)。冰块只能沿网格方向推动。
请你帮助他们以最少的推动次数将冰块推入深洞中。
格式
输入格式
输入文件第一行为冰山的个数N (1<=N<=4000),第二行为冰块开始所在的方格坐标X1,Y1,第三行为深洞所在的方格坐标X2,Y2,以下N行每行有四个数,分别是每个冰山所占的格子左上角和右下角坐标Xi1,Yi1,Xi2,Yi2
输出格式
输出文件仅包含一个整数,为最少推动冰块的次数。如果无法将冰块推入深洞中,则输出0。
样例1
样例输入1[复制]
2
1 1
5 5
1 3 3 3
6 2 8 4
样例输出1[复制]
3
限制
各个测试点1s
解题过程:
当时自己也没多想,于是就敲了个bfs暴力,结果不幸的是while循环崩了,而且写的还不是正解。。于是。。结果你懂得
以下是我考试时的代码:
#include<cstdio>#include<cstdlib>int n,i,j,k,x1,y1,x2,y2,d,t1,t2,t3,t4,g=1;int f[3][1000001];bool b[2001][2001];int way[5][2]={0,0,-1,0,0,-1,0,1,1,0};void pd(int n){ if(f[0][n]==x2&&f[1][n]==y2) { printf("%d",d); exit(0); }}void bfs(int begin,int end){ int i,j; for(i=begin;i<=end;i++) pd(i); int x,y; for(i=begin;i<=end;i++) for(j=1;j<=4;j++) { if(f[2][i]+j==5) continue; x=f[0][i];y=f[1][i]; while(1) {x+=way[j][0];y+=way[j][1];if(b[x][y]) break;}//这个while循环崩掉了// while(!b[x+way[j][0]][y+way[j][1]]) {x+=way[j][0];y+=way[j][1];if(x==1999||y==1999) break;} if(x==0||x==2000||y==0||y==2000) continue; x-=way[j][0];y-=way[j][1]; f[0][++g]=x; f[1][g]=y; f[2][g]=j; } d++; if(g>end) bfs(end+1,g);}main(){ freopen("ice.in","r",stdin); freopen("ice.out","w",stdout); scanf("%d%d%d%d%d",&n,&x1,&y1,&x2,&y2); for(k=1;k<=n;k++) { scanf("%d%d%d%d",&t1,&t2,&t3,&t4); for(i=t1;i<=t3;i++) b[i][t2]=b[i][t4]=1; for(i=t2;i<=t4;i++) b[t1][i]=b[t3][i]=1; } for(i=0;i<=2000;i++) b[i][0]=b[0][i]=b[i][2000]=b[2000][i]=1; f[0][1]=x1;f[1][1]=y1;f[2][1]=233; bfs(1,1); printf("0");}
我一开始的思路很简单,就是用一个布尔矩阵模拟。然而人家毕竟是CTSC出的题,再怎么着也不至于这么水呀,于是人家就故意不谢坐标范围。
下午老师讲题以后我又重做了一遍。一开始我自己脑补了一个坐标系,然而写完以后测试样例的时候发现程序死了。这让我一脸懵逼,画出图来一看,这个题目的描述简直有毒!我就不描述了,见图:
可以看到,这个坐标系里面x轴是竖着的,y轴是横着的。这和我想象的一点也不符合。
我相信,只要是一个正常人,看完样例以后一定会先想到的是这个样子。然而就像图里标出来的,左上和右下是矛盾的,这就很蛋疼了。我的代码本来是这个样子:
#include<cstdio>#include<cstdlib>#include<cstring>long long n,i,j,x1,y1,x2,y2,d,g=1,t,p;struct aa{ int x1,y1,x2,y2;}a[4002];bool b[4002][5];int f[16002][3];void pd(int n){ if(f[n][0]==x2&&f[n][1]==y2) { printf("%d",d); exit(0); }}int findl(int x,int y){ int i,s=1e9,p=1e9+7;//s:距离 for(i=1;i<=n;i++) if(a[i].x2<x&&x-a[i].x2<s&&a[i].y1<=y&&y<=a[i].y2) { s=x-a[i].x2; p=i; } return p;}int findr(int x,int y){ int i,s=1e9,p=1e9+7; for(i=1;i<=n;i++) if(a[i].x1>x&&a[i].x1-x<s&&a[i].y1<=y&&y<=a[i].y2)//不是a[i].y1<=y&&y<=a[i].y2,注意 { s=a[i].x1-x; p=i; } return p;}int findu(int x,int y){ int i,s=1e9,p=1e9+7; for(i=1;i<=n;i++) if(a[i].y2>y&&a[i].y2-y<s&&a[i].x1<=x&&x<=a[i].x2) { s=a[i].y2-y; p=i; } return p;}int findd(int x,int y){ int i,s=1e9,p=1e9+7; for(i=1;i<=n;i++) if(a[i].y1<y&&y-a[i].y1<s&&a[i].x1<=x&&x<=a[i].x2) { s=y-a[i].y1; p=i; } return p;}void bfs(int begin,int end){ int i,p; for(i=begin;i<=end;i++) pd(i); for(i=begin;i<=end;i++) if(i==1) { p=findu(f[1][0],f[1][1]); if(p!=1e9+7) { f[++g][0]=f[1][1]; f[g][1]=a[p].y2-1; f[g][2]=2;//在下面 } p=findd(f[1][0],f[1][1]); if(p!=1e9+7) { f[++g][0]=f[1][1]; f[g][1]=a[p].y1+1; f[g][2]=1;//在上面 } p=findl(f[1][0],f[1][1]); if(p!=1e9+7) { f[++g][0]=f[1][0]; f[g][1]=a[p].x2+1; f[g][2]=4;//在右面 } p=findr(f[1][0],f[1][1]); if(p!=1e9+7) { f[++g][0]=f[1][0]; f[g][1]=a[p].x1-1; f[g][2]=3;//在左面 } } else//现在贴在某一冰山上 if(f[i][2]==1||f[i][2]==2)//现在只能左右滑动 { p=findl(f[i][0],f[i][1]); if(p!=1e9+7) { f[++g][0]=f[i][0]; f[g][1]=a[p].x2+1; f[g][2]=4; } p=findr(f[i][0],f[i][1]); if(p!=1e9+7) { f[++g][0]=a[p].x1-1; f[g][1]=f[i][1]; f[g][2]=3; } } else//现在只能上下滑动 { p=findu(f[i][0],f[i][1]); if(p!=1e9+7) { f[++g][0]=a[p].y2-1; f[g][1]=f[i][1]; f[g][2]=2; } p=findd(f[i][0],f[i][1]); if(p!=1e9+7) { f[++g][0]=a[p].y1+1; f[g][1]=f[i][1]; f[g][2]=1; } } d++; bfs(end+1,g);}main(){ scanf("%d%d%d%d%d",&n,&x1,&y1,&x2,&y2); for(i=1;i<=n;i++) scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2); a[++n].x1=x2;a[n].x2=x2;a[n].y1=a[n].y2=y2; memset(b,1,sizeof(b)); f[1][0]=x1;f[1][1]=y1;f[1][2]=-1; bfs(1,1); printf("0");}
本蒟蒻修改了n遍程序仍然死循环,这时候有好心人提醒我说,不要管原图的错误,按照上面的编就行了。修改后的find是这个样子:
int findl(int x,int y){ int i,s=1e9,p=1e9+7;//s:距离 for(i=1;i<=n;i++) if(a[i].y2<y&&y-a[i].y2<s&&a[i].x1<=x&&x<=a[i].x2) { s=y-a[i].y2; p=i; } return p;}int findr(int x,int y){ int i,s=1e9,p=1e9+7; for(i=1;i<=n;i++) if(a[i].y1>y&&a[i].y1-y<s&&a[i].x1<=x&&x<=a[i].x2) { s=a[i].y1-y; p=i; } return p;}int findu(int x,int y){ int i,s=1e9,p=1e9+7; for(i=1;i<=n;i++) if(x>a[i].x2&&x-a[i].x2<s&&a[i].y1<=y&&y<=a[i].y2) { s=x-a[i].x2; p=i; } return p;}int findd(int x,int y){ int i,s=1e9,p=1e9+7; for(i=1;i<=n;i++) if(x<a[i].x1&&a[i].x1-x<s&&a[i].y1<=y&&y<=a[i].y2) { s=a[i].x1-x; p=i; } return p;}
然而这样仍然是错误的。为什么呢?因为我是把结束点也就是深洞当做一个冰山来看待的,这也就导致程序能成功地找到通向洞口最近的路,但并不能停止递归,于是成功地导致了死循环。继续修改,代码成了这个样子:
#include<cstdio>#include<cstdlib>#include<cstring>long long n,i,j,x1,y1,x2,y2,d,g=1,t,p;struct aa{ int x1,y1,x2,y2;}a[4002];bool b[4002][5];int f[16002][3];void print(){ printf("%d",d); exit(0);}int findl(int x,int y){ int i,s=1e9,p=1e9+7;//s:距离 for(i=1;i<=n;i++) if(a[i].y2<y&&y-a[i].y2<s&&a[i].x1<=x&&x<=a[i].x2) { if(i==n) print(); s=y-a[i].y2; p=i; } return p;}int findr(int x,int y){ int i,s=1e9,p=1e9+7; for(i=1;i<=n;i++) if(a[i].y1>y&&a[i].y1-y<s&&a[i].x1<=x&&x<=a[i].x2) { if(i==n) print(); s=a[i].y1-y; p=i; } return p;}int findu(int x,int y){ int i,s=1e9,p=1e9+7; for(i=1;i<=n;i++) if(x>a[i].x2&&x-a[i].x2<s&&a[i].y1<=y&&y<=a[i].y2) { if(i==n) print(); s=x-a[i].x2; p=i; } return p;}int findd(int x,int y){ int i,s=1e9,p=1e9+7; for(i=1;i<=n;i++) if(x<a[i].x1&&a[i].x1-x<s&&a[i].y1<=y&&y<=a[i].y2) { if(i==n) print(); s=a[i].x1-x; p=i; } return p;}void bfs(int begin,int end){ int i,p; d++; for(i=begin;i<=end;i++) if(i==1) { p=findu(f[1][0],f[1][1]); if(p!=1e9+7&&b[p][2]) { f[++g][0]=a[p].x2+1; f[g][1]=f[1][1]; f[g][2]=2;//在下面 b[p][2]=0; } p=findd(f[1][0],f[1][1]); if(p!=1e9+7&&b[p][1]) { f[++g][0]=a[p].x1-1; f[g][1]=f[1][1]; f[g][2]=1;//在上面 b[p][1]=0; } p=findl(f[1][0],f[1][1]); if(p!=1e9+7&&b[p][4]) { f[++g][0]=f[1][0]; f[g][1]=a[p].y2+1; f[g][2]=4;//在右面 b[p][4]=0; } p=findr(f[1][0],f[1][1]); if(p!=1e9+7&&b[p][3]) { f[++g][0]=f[1][0]; f[g][1]=a[p].y1-1; f[g][2]=3;//在左面 b[p][3]=0; } } else//现在贴在某一冰山上 if(f[i][2]==1||f[i][2]==2)//现在只能左右滑动 { p=findl(f[i][0],f[i][1]); if(p!=1e9+7&&b[p][4]) { f[++g][0]=f[i][0]; f[g][1]=a[p].y2+1; f[g][2]=4; b[p][4]=0; } p=findr(f[i][0],f[i][1]); if(p!=1e9+7&&b[p][3]) { f[++g][0]=f[i][0]; f[g][1]=a[p].y1-1; f[g][2]=3; b[p][3]=0; } } else//现在只能上下滑动 { p=findu(f[i][0],f[i][1]); if(p!=1e9+7&&b[p][2]) { f[++g][0]=a[p].x2+1; f[g][1]=f[i][1]; f[g][2]=2; b[p][2]=0; } p=findd(f[i][0],f[i][1]); if(p!=1e9+7&&b[p][1]) { f[++g][0]=a[p].x1-1; f[g][1]=f[i][1]; f[g][2]=1; b[p][1]=0; } } bfs(end+1,g);}main(){ scanf("%d%d%d%d%d",&n,&x1,&y1,&x2,&y2); for(i=1;i<=n;i++) scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2); a[++n].x1=x2;a[n].x2=x2;a[n].y1=a[n].y2=y2; memset(b,1,sizeof(b)); f[1][0]=x1;f[1][1]=y1;f[1][2]=-1; bfs(1,1); printf("0");}
然而还是WA。经过反复查看,我发现我的程序在无解时是会无限递归下去的,于是主程序里的那个printf(“0”)并无卵用。所以我在每一个find里都加入了一个判断(举个例子):
void print(){ printf("%d",d); exit(0);}int findl(int x,int y){ int i,s=1e9,p=1e9+7;//s:距离 for(i=1;i<=n;i++) if(a[i].y2<y&&y-a[i].y2<s&&a[i].x1<=x&&x<=a[i].x2) { if(i==n) print(); s=y-a[i].y2; p=i; } return p;}
其实我也应该反思一下,考试的时候自己为什么没有想到可以不用布尔数组?那样的话适应范围是很小的。后来重做的时候一开始我忘记了使用判重数组,这又意味着什么?没有及时推出递归导致死循环,说明我在做题的时候还是没有很好地理解题意。
- CTSC2000 冰原探险
- [BZOJ2541][Ctsc2000]冰原探险(bfs)
- 【bzoj 2541】 [Ctsc2000]冰原探险(BFS)
- bzoj 2541: [Ctsc2000]冰原探险 (bfs+建图)
- 构图(+BFS)——BZOJ2541/Luogu3716 [CTSC2000]冰原探险
- BZOJ2539: [Ctsc2000]丘比特的烦恼
- 宝岛探险
- 宝岛探险
- 宝岛探险
- 丛林探险
- 探险计划
- 探险计划
- 灵岩山探险
- 【JZOJ2702】探险
- [codevs1725]探险
- 丛林探险
- [BZOJ2539][CTSC2000][KM]丘比特的烦恼
- 【hdu4844 && bzoj2538】【Ctsc2000】【DP优化】公路巡逻
- 面向对象基础(二)
- hdu 1398 普通母函数
- 数字滤波技术
- Android进程优先级以及线程间通信方式
- PS基础学习
- CTSC2000 冰原探险
- 【UML】活动图中的线
- GDB调试器的命令应用
- win10安装CAJViewer 错误1305
- java基础11(Javaoo6)——接口
- abs,int与round函数
- 【Android】12、全屏显示
- 软件工程视频第四章
- PWM协议