BZOJ 1020 安全的航线flight
Description
在设计航线的时候,安全是一个很重要的问题。首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率。当飞机迫降到海上的时候,最近的陆地就是一个关键的因素。航线中最危险的地方就是距离最近的陆地最远的地方,我们称这种点为这条航线“孤地点”。孤地点到最近陆地的距离被称为“孤地距离”。作为航空公司的高级顾问,你接受的第一个任务就是尽量找出一条航线的孤地点,并计算这条航线的孤地距离。为了简化问题,我们认为地图是一个二维平面,陆地可以用多边形近似,飞行线路为一条折线。航线的起点和终点都在陆地上,但中间的转折点是可能在海上(如下图所示,方格标示出了孤地点)。
Input
输入的第一行包括两个整数C和N(1≤C≤20,2≤N≤20),分别代表陆地的数目的航线的转折点的数目。接下来有N行,每行有两个整数x,y。(x,y)表示一个航线转折点的坐标,第一个转折点为航线的起点,最后一个转折点为航线的终点。接下来的输入将用来描述C块大陆。每块输入由一个正整数M开始(M≤30),M表示多边形的顶点个数,接下来的M行,每行会包含两个整数x,y,(x,y)表示多边形的一个顶点坐标,我们保证这些顶点以顺时针或逆时针给出了该多边形的闭包,不会出现某些边相交的情况。此外我们也保证输入数据中任何两块大陆不会相交。输入的所有坐标将保证在-10000到10000的范围之间。
Output
输出一个浮点数,表示航线的孤地距离,数据保留2位小数。
Sample Input
-9 -6
5 1
3
0 16
-16 -12
17 -6
Sample Output
- 先将所有不在多边形内部的线段加入队列中;
- 取出队首线段,找出与左端点最近的多边形上的点p1,右端点最近的多边形上的点p2。ans = max(ans,dis(p1,左端点),dis(p2,右端点));
- 在线段上二分出一个点p,使得dis(p,p1) == dis(p,p2);
- 若dis(p,p1) < ans,continue;否则,将线段二等分加入队列中;
- 重复2,3,4直到队列为空;
算法(减枝)就是这样。为什么这样是对的呢?我们证明一下:
我们现在要讨论的就是这个算法的正确性
现在我们有一条线段和对应的p1和p2,分别是左端点最近的点和右端点最近的点
有三种情况
然后我们发现线段上的点到自己最近点的距离不会超过max(dis(p1,p),dis(a,p1),(b,p2))(a,b分别为线段的左右端点)
所以我们的删除操作是对的,我们删除的都是不会更新答案的线段,就像ydc说的一样,这个就像是搜索剪枝
(注:上述证明转自:http://www.cnblogs.com/Randolph87/p/3642917.html)
最后再贴一份自己丑丑的代码:
1 #include<algorithm> 2 #include<cmath> 3 #include<queue> 4 #include<cstdio> 5 #include<cstdlib> 6 #include<iostream> 7 using namespace std; 8 9 #define rhl 10001 10 #define esp (1e-4) 11 #define maxn (30) 12 #define maxc (30) 13 #define maxm (40) 14 int tot,n,c,have[maxc]; double ans; 15 16 inline double equal(double a,double b) { return fabs(a-b) < esp; } 17 18 inline bool dd(double a,double b) { if (equal(a,b)) return true; return a >= b; } //>= 19 20 inline bool xd(double a,double b) { if (equal(a,b)) return true; return a <= b; } //<= 21 22 struct NODE 23 { 24 double x,y; 25 friend inline bool operator == (NODE a,NODE b) { return equal(a.x,b.x)&&equal(a.y,b.y); } 26 friend inline bool operator < (NODE a,NODE b) 27 { 28 if (a.x != b.x) return a.x < b.x; 29 else return a.y < b.y; 30 } 31 inline NODE ra() 32 { 33 int xx,yy; 34 do xx = rand()%rhl,yy = rand()%rhl; 35 while (equal(1.0*xx,x)||equal(1.0*yy,y)); 36 return (NODE) {1.0*xx,1.0*yy}; 37 } 38 inline void read() { scanf("%lf %lf",&x,&y); } 39 }pol[maxc][maxm],bac[maxc*maxm]; 40 struct LINE 41 { 42 double a,b,c; 43 friend inline bool operator ==(LINE l1,LINE l2) { return equal(l1.a*l2.c,l2.a*l1.c); } 44 inline LINE vert(NODE p) { return (LINE) {b,-a,a*p.y-b*p.x}; } 45 inline bool on(NODE p) { return equal(0,a*p.x+b*p.y+c); } 46 }; 47 struct SEG{ 48 NODE a,b; 49 inline NODE MID() { return (NODE) {(a.x+b.x)/2,(a.y + b.y)/2}; } 50 inline bool exist() { return !(a == b); } 51 inline LINE extend() { return (LINE) {a.y-b.y,b.x-a.x,b.y*(a.x-b.x)-b.x*(a.y-b.y)}; } 52 inline bool on(NODE p) 53 { 54 if (p == a) return true; 55 if (p == b) return true; 56 return (dd(p.x,min(a.x,b.x))&xd(p.x,max(a.x,b.x)))&&(dd(p.y,min(a.y,b.y))&xd(p.y,max(a.y,b.y))); 57 } 58 }temp[maxn]; 59 queue <SEG> team; 60 61 inline bool para(LINE l1,LINE l2) { return equal(l1.a * l2.b,l1.b * l2.a); } 62 63 inline double qua(double a) { return a * a; } 64 65 inline double dis(NODE a,NODE b) { return sqrt(qua(a.x - b.x)+qua(a.y - b.y)); } 66 67 inline NODE cp(LINE l1,LINE l2) 68 { 69 double a1 = l1.a,b1 = l1.b,c1 = l1.c; 70 double a2 = l2.a,b2 = l2.b,c2 = l2.c; 71 double ry = (c2*a1-c1*a2)/(b1*a2-b2*a1),rx = (c1*b2-c2*b1)/(b1*a2-b2*a1); 72 return (NODE) {rx,ry}; 73 } 74 75 inline void cross(SEG s,int now) 76 { 77 LINE l = s.extend(),l1; SEG t; NODE p; NODE tt[maxm]; 78 int cnt = 0; 79 for (int i = 1;i <= have[now];++i) 80 { 81 t = (SEG) {pol[now][i],pol[now][i-1]}; 82 l1 = t.extend(); 83 if (para(l,l1)) 84 { 85 if (l == l1) 86 { 87 if (s.on(t.a)) tt[++cnt] = t.a; 88 if (s.on(t.b)) tt[++cnt] = t.b; 89 } 90 continue; 91 } 92 p = cp(l,l1); 93 if (t.on(p) && s.on(p)) 94 tt[++cnt] = p; 95 } 96 sort(tt+1,tt+cnt+1); 97 for (int i = 1;i <= cnt;++i) bac[++tot] = tt[i]; 98 } 99 100 inline NODE find(NODE p) 101 { 102 NODE ret,q; LINE l1,l2; SEG s; double best = 1e9,len; 103 for (int i = 1;i <= c;++i) 104 for (int j = 1;j <= have[i];++j) 105 { 106 s = (SEG) {pol[i][j],pol[i][j-1]}; 107 l1 = s.extend(); 108 l2 = l1.vert(p); 109 q = cp(l1,l2); 110 if (s.on(q)) 111 { 112 len = dis(p,q); 113 if (best > len) ret = q,best = len; 114 } 115 else 116 { 117 if (dis(p,s.a) < dis(p,s.b)) q = s.a; 118 else q = s.b; 119 len = dis(p,q); 120 if (best > len) ret = q,best = len; 121 } 122 } 123 return ret; 124 } 125 126 inline bool in(NODE p) 127 { 128 NODE q = p.ra(); SEG s = (SEG) {p,q},t; LINE l = s.extend(),l1; int cnt; 129 for (int i = 1;i <= c;++i) 130 { 131 cnt = 0; 132 for (int j = 1;j <= have[i];++j) 133 { 134 t = (SEG) {pol[i][j],pol[i][j-1]}; 135 if ((t.extend()).on(p)&&t.on(p)) return false; 136 l1 = t.extend(); 137 if (para(l,l1)) continue; 138 q = cp(l,l1); 139 if (dd(q.x,p.x)&&t.on(q)) ++cnt; 140 } 141 if (cnt & 1) return true; 142 } 143 return false; 144 } 145 146 inline void init() 147 { 148 for (int i = 1;i < n;++i) 149 { 150 tot = 0; 151 if (!(temp[i].a < temp[i].b)) swap(temp[i].a,temp[i].b); 152 for (int j = 1;j <= c;++j) 153 cross(temp[i],j); 154 if (!in(temp[i].a)) bac[++tot] = temp[i].a; 155 if (!in(temp[i].b)) bac[++tot] = temp[i].b; 156 sort(bac+1,bac+tot+1); 157 for (int j = 1;j < tot;j++) 158 if (!in((SEG){bac[j],bac[j+1]}.MID())) 159 team.push((SEG){bac[j],bac[j+1]}); 160 } 161 } 162 163 inline void work() 164 { 165 SEG now; NODE mid,p1,p2,l,r; double ret; 166 while (!team.empty()) 167 { 168 now = team.front(); team.pop(); 169 if (!now.exist()) continue; 170 p1 = find(now.a); p2 = find(now.b); 171 l = now.a,r = now.b; 172 while (!(l == r)) 173 { 174 mid = ((SEG){l,r}).MID(); 175 if (dis(p1,mid) > dis(p2,mid)) r = mid; 176 else l = mid; 177 } 178 ret = dis(r,p1); 179 ans = max(max(dis(now.a,p1),dis(now.b,p2)),ans); 180 if (ret-esp < ans) continue; 181 mid = now.MID(); 182 team.push((SEG){now.a,mid}),team.push((SEG){mid,now.b}); 183 } 184 } 185 186 int main() 187 { 188 srand(233); 189 ans = 0; 190 scanf("%d %d ",&c,&n); 191 NODE p1,p2; p1.read(); 192 for (int i = 2;i <= n;++i) 193 { 194 p2.read(); temp[i-1] = (SEG) {p1,p2}; 195 p1 = p2; 196 } 197 for (int i = 1;i <= c;++i) 198 { 199 scanf("%d ",have+i); 200 for (int j = 1;j <= have[i];++j) pol[i][j].read(); 201 pol[i][0] = pol[i][have[i]]; 202 } 203 init(); 204 work(); 205 printf("%.2lf\n",ans); 206 fclose(stdin); fclose(stdout); 207 return 0; 208 }