poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399
http://acm.hit.edu.cn/hoj/problem/view?id=1037
题意:
在一个最多200*200的minecraft方块地图上(由很多1*1*1的方块搭起来的地图,最高5000),其中两块分别有高0.5米的激光塔,有一个高0.5米的机器人要从其中一个激光塔走到另一个。要求只能走相邻4个方向,每次不能爬上超过1格或跳下超过3格(咦,好像真的很像minecraft),要求每走到一个格子,机器人站在在这个格子的中心,能直接接收到至少一个激光塔照射(机器人的头顶与激光塔的顶部连成的直线没有被地形挡住)。
还有就是,地形有缝隙,例如:
1 9
9 1
这样的2*2的地图,在两个高度为1的地形上是可以互相接收到激光的,因为两个9之间有条缝。
题解:
宽搜走路,难点在于判断一格是否能走。
最关键的函数:判断两个格子A、B之间是否被挡。
可分为两部分判断:
1.以x轴为基准,x=Ax,x=Ax+1,x=Ax+2……x=Bx。针对每个x,计算得出浮点数Y(由激光在地平面上的斜率计算得到),可以通过floor(向下取整)得到整数y,得到激光经过(x,y) 和(x+1, y)两个格子之间的交界处,通过这两个格子的高度和激光当时的高度(由激光在竖直切面的斜率计算得到),判断是否被遮挡。
2.以y轴为基准,同上。
上面只说了没有通过缝隙的情况。若发现Y为整数,则是通过了缝隙,在x为轴的情况下,此时改为判断(x,floor(Y-0.5p))和(x+1,floor(Y+0.5p)),p为1或-1,与地平面斜率同号。以y为轴类似。
这个函数写对了其他就简单了。
-------------------------------------------------------------------
这题就难在判断光线可见,建议解题时画出平面图,写出代数公式,研究各种情况的通用判断方法。
程序过不了样例,就调试观察判断激光可见的过程,找到错误。
我写的时候出的错主要在x轴y轴分类讨论有问题、对缝隙情况判断有问题。
代码见下,我写得屁滚尿流,有很多地方有简化得更加清晰明了的余地,仅供参考
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 #define RD(x) scanf("%d",&x) 7 #define REP(i,n) for(i=0;i<n;i++) 8 const int MAXN=222; 9 const int g[2][4]= {{0,0,1,-1},{-1,1,0,0}}; 10 const double eps=1e-5; 11 int n,m; 12 int a[MAXN][MAXN]; 13 int p[2][2]; 14 bool visited[MAXN][MAXN]; 15 int seeChecked[MAXN][MAXN]; 16 bool ok(int now[2], int next[2]) { 17 int y=next[1], x=next[0]; 18 int h1=a[now[0]][now[1]]; 19 int h2=a[next[0]][next[1]]; 20 if(x<0 || y<0 || x>=n || y>=m)return false; 21 if(h2-h1>1 || h1-h2>3)return false; 22 return true; 23 } 24 25 bool canSee2Dot(int x1,int y1,int x2,int y2) { 26 bool re=true; 27 int k; 28 int p[2][2]; 29 p[0][0]=x1; 30 p[0][1]=y1; 31 p[1][0]=x2; 32 p[1][1]=y2; 33 // printf("(%d,%d)->(%d,%d)\n",x1,y1,x2,y2); 34 REP(k,2) { 35 int st0=p[0][k],ed0=p[1][k]; 36 int st1=p[0][k^1], ed1= p[1][k^1]; 37 if(st0==ed0)continue; 38 if(ed0<st0) { 39 swap(ed0,st0); 40 swap(ed1,st1); 41 } 42 // printf("k=%d,%d->%d\n",k,st0,ed0); 43 double kk=ed1-st1; 44 kk/=ed0-st0; 45 double hk=a[ed0][ed1] - a[st0][st1]; 46 if(k==1)hk=a[ed1][ed0]-a[st1][st0]; 47 hk/=ed0-st0; 48 double now = st1 + 0.5 + 0.5*kk; 49 double nowh = a[st0][st1] + 0.5 + 0.5 * hk; 50 if(k==1)nowh = a[st1][st0] + 0.5 + 0.5*hk; 51 // printf("%d,%d,%f,%f\n",st0,st1,hk,nowh); 52 for(int i=st0; i<ed0; i++) { 53 int theNow = floor(now); 54 int theX,theY; 55 double theH1,theH2; 56 if(fabs(now-round(now))>eps) { 57 if(k==0) { 58 theX=i; 59 theY=theNow; 60 theH1=a[theX][theY]; 61 theH2=a[theX+1][theY]; 62 } else { 63 theX=theNow; 64 theY=i; 65 theH1=a[theX][theY]; 66 theH2=a[theX][theY+1]; 67 } 68 // printf("%d,%d,%f,%f,%f,(%f)\n",theX,theY,theH1,theH2,nowh,now); 69 70 } else { 71 if(k==0) { 72 theX=i; 73 theY=floor(now-0.5*fabs(kk)/kk); 74 theH1=a[theX][theY]; 75 theH2=a[theX+1][(int)floor(now+0.5*fabs(kk)/kk)]; 76 } else { 77 theX=floor(now-0.5*fabs(kk)/kk); 78 theY=i; 79 theH1=a[theX][theY]; 80 theH2=a[(int)floor(now+0.5*fabs(kk)/kk)][theY+1]; 81 } 82 // printf("%d,%d,%f,%f,%f,(%f)\n",theX,theY,theH1,theH2,nowh,now); 83 } 84 if(theH1>nowh || theH2>nowh) { 85 re=false; 86 break; 87 } 88 now+=kk; 89 nowh+=hk; 90 } 91 if(!re)break; 92 } 93 return re; 94 } 95 96 bool canSee(int d[2]) { 97 int x=d[0], y=d[1]; 98 if(seeChecked[x][y]!=-1)return seeChecked[x][y]; 99 bool re=canSee2Dot(x,y,p[0][0],p[0][1]) || canSee2Dot(x,y,p[1][0],p[1][1]); 100 seeChecked[x][y]=re; 101 return re; 102 } 103 int farm() { 104 int b[MAXN*MAXN][3]; 105 int bl=0,br=1; 106 int i; 107 if(p[0][0]==p[1][0] && p[0][1]==p[1][1])return 0; 108 memset(visited,0,sizeof(visited)); 109 memset(seeChecked,-1,sizeof(seeChecked)); 110 b[0][0]=p[0][0]; 111 b[0][1]=p[0][1]; 112 while(bl<br) { 113 int now[3]; 114 now[0]=b[bl][0]; 115 now[1]=b[bl][1]; 116 now[2]=b[bl][2]; 117 // printf("now(%d,%d)\n", now[0],now[1]); 118 bl++; 119 REP(i,4) { 120 int next[3]; 121 next[0] = now[0]+g[0][i]; 122 next[1] = now[1]+g[1][i]; 123 next[2] = now[2]+1; 124 if(!visited[next[0]][next[1]] && ok(now,next) && canSee(next)) { 125 if(next[0]==p[1][0] && next[1]==p[1][1])return next[2]; 126 b[br][0]=next[0]; 127 b[br][1]=next[1]; 128 b[br][2]=next[2]; 129 br++; 130 visited[next[0]][next[1]]=true; 131 } 132 } 133 } 134 return -1; 135 } 136 137 int main() { 138 int T,i,j; 139 int x; 140 RD(T); 141 while(T--) { 142 scanf("%d%d",&n,&m); 143 REP(i,n)REP(j,m)RD(a[i][j]); 144 scanf("%d%d%d%d",&p[0][0],&p[0][1], &p[1][0], &p[1][1]); 145 p[0][0]--; 146 p[0][1]--; 147 p[1][0]--; 148 p[1][1]--; 149 x = farm(); 150 if(x!=-1)printf("The shortest path is %d steps long.\n",x); 151 else printf("Mission impossible!\n"); 152 } 153 return 0; 154 }