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 }
View Code

 

posted @ 2016-05-08 03:59  带鱼Yuiffy  阅读(336)  评论(0编辑  收藏  举报