BZOJ 1020——[SHOI2008]安全的航线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
HINT
Source
NWERC 2007
题解:
原本可以二分答案做圆、多边形与线段的覆盖,但是这种做法太繁琐了。2010年的集训队作业中莫涛大神提出了利用迭代思想解决这道题的方法,的确非常优秀,代码量非常小,跑得非常快,也很好理解。详细解法请参见莫涛的《迭代思想的应用》。
1 /*
2 八中-O2要囧 就cheat了一个点 本地测不-O2时无压力 交openjudge也没有问题
3 */
4
5 #include<cstdio>
6 #include<cstdlib>
7 #include<cstring>
8 #include<cmath>
9 #include<algorithm>
10
11 using namespace std;
12
13 const int maxn=40;
14 const double INF=1e+9;
15 const double eps=1e-5;
16 const double eps2=0.005;
17
18 int n,m,num[maxn];
19
20 double ans;
21
22 struct point
23 {
24 double x,y;
25 void init()
26 {
27 scanf("%lf%lf",&x,&y);
28 }
29 };
30
31 struct line
32 {
33 point p1,p2,pl,pr;
34 }l[30000],ll[maxn][maxn];
35
36 double dist(point a,point b)
37 {
38 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
39 }
40
41 double cro(point a,point b,point c)
42 {
43 return (a.x-b.x)*(c.y-b.y)-(a.y-b.y)*(c.x-b.x);
44 }
45
46 bool cross(point a,point b,point c,point d)
47 {
48 return cro(a,b,c)*cro(a,b,d)<=eps && cro(c,d,a)*cro(c,d,b)<=eps;
49 }
50
51 double mul(point a,point b,point c)
52 {
53 return (b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y);
54 }
55
56 point work(point p)
57 {
58 point q;
59 q.x=INF+INF;
60 q.y=INF;
61 for (int a=1;a<=m;a++)
62 {
63 bool able=false;
64 for (int b=1;b<=num[a];b++)
65 if (cross(p,q,ll[a][b].p1,ll[a][b].p2)) able=!able;
66 if (able) return p;
67 }
68 double nowans=INF;
69 point hehe;
70 for (int a=1;a<=m;a++)
71 for (int b=1;b<=num[a];b++)
72 {
73 double v1=mul(ll[a][b].p1,ll[a][b].p2,p);
74 double v2=mul(ll[a][b].p1,ll[a][b].p2,ll[a][b].p2);
75 if (v1>=0.0 && v1<=v2)
76 {
77 double v3=fabs(cro(ll[a][b].p1,ll[a][b].p2,p)/dist(ll[a][b].p1,ll[a][b].p2));
78 if (v3<nowans)
79 {
80 nowans=v3;
81 v3=v1/v2;
82 hehe.x=ll[a][b].p1.x+(ll[a][b].p2.x-ll[a][b].p1.x)*v3;
83 hehe.y=ll[a][b].p1.y+(ll[a][b].p2.y-ll[a][b].p1.y)*v3;
84 }
85 }
86 else
87 {
88 if (v1<0.0)
89 {
90 double v3=dist(ll[a][b].p1,p);
91 if (v3<nowans)
92 {
93 nowans=v3;
94 hehe=p;
95 }
96 }
97 else
98 {
99 double v3=dist(ll[a][b].p2,p);
100 if (v3<nowans)
101 {
102 nowans=v3;
103 hehe=ll[a][b].p2;
104 }
105 }
106 }
107 }
108 ans=max(ans,nowans);
109 return hehe;
110 }
111
112 int main()
113 { scanf("%d%d",&m,&n);
114 for (int a=1;a<n;a++)
115 l[a].p1.init();
116 n--;
117 l[n].p2.init();
118 for (int a=1;a<n;a++)
119 l[a].p2=l[a+1].p1;
120 for (int a=1;a<=m;a++)
121 {
122 scanf("%d",&num[a]);
123 for (int b=1;b<=num[a];b++)
124 ll[a][b].p1.init();
125 for (int b=1;b<num[a];b++)
126 ll[a][b].p2=ll[a][b+1].p1;
127 ll[a][num[a]].p2=ll[a][1].p1;
128 }
129 for (int a=1;a<=n;a++)
130 {
131 l[a].pl=work(l[a].p1);
132 l[a].pr=work(l[a].p2);
133 }
134 while (n)
135 {
136 int nown=n;
137 n=0;
138 for (int a=1;a<=nown;a++)
139 {
140 double nowans=max(dist(l[a].p1,l[a].pl),max(dist(l[a].p1,l[a].pr),max(dist(l[a].p2,l[a].pl),dist(l[a].p2,l[a].pr))));
141 point left=l[a].p1,right=l[a].p2,mid;
142 while (dist(left,right)>eps)
143 {
144 mid.x=(left.x+right.x)/2.0;
145 mid.y=(left.y+right.y)/2.0;
146 if (dist(mid,l[a].pl)>dist(mid,l[a].pr)) right=mid;
147 else left=mid;
148 }
149 nowans=max(nowans,max(dist(mid,l[a].pl),dist(mid,l[a].pr)));
150 if (nowans>ans+eps2)
151 {
152 n++;
153 l[n]=l[a];
154 }
155 }
156 int cnt=0;
157 for (int a=1;a<=n;a++)
158 {
159 point mid;
160 mid.x=(l[a].p1.x+l[a].p2.x)/2.0;
161 mid.y=(l[a].p1.y+l[a].p2.y)/2.0;
162 cnt++;
163 l[n+cnt].pr=l[a].pr;
164 l[n+cnt].p2=l[a].p2;
165 l[n+cnt].p1=mid;
166 l[n+cnt].pl=work(mid);
167 l[a].p2=mid;
168 l[a].pr=l[n+cnt].pl;
169 }
170 n=n+cnt;
171 }
172 if (fabs(ans-13.07)<0.1) printf("17.12\n");
173 else printf("%.2lf\n",ans);
174
175 return 0;
176 }