首先对于给定的折线求出可行区域的半平面交,可行区域指所有的点p的集合,满足点p出发的射线可以在不与折线提前相交的前提下能够到达折线上的每一个点。
然后就变成上面一个折线y1,下面一个折线y2,求y1-y2的最小值了。一次分段函数的差是分段函数,而显然一次分段函数的最小值在端点取到。没了。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 1005
using namespace std;
struct point{ double x,y; }a[N],b[N];
struct line{ point p,v; double k; }q[N],l[N]; int n,cnt;
point operator -(point u,point v){
point t; t.x=u.x-v.x; t.y=u.y-v.y; return t;
}
double crs(point u,point v){ return u.x*v.y-u.y*v.x; }
point itr(line x,line y){
double t=crs(y.p-x.p,y.v)/crs(x.v,y.v);
x.p.x+=x.v.x*t; x.p.y+=x.v.y*t; return x.p;
}
double valx(point u,point v,double x){
return u.y+(x-u.x)/v.x*v.y;
}
bool ok(line x,line y,line t){
return crs(t.v,itr(x,y)-t.p)<0;
}
bool cmp(line x,line y){
return x.k<y.k || x.k==y.k && crs(x.p-y.p,y.v)<0;
}
void bpmj(){
sort(l+1,l+cnt+1,cmp); int head=1,tail=0,i; cnt=1;
for (i=2; i<=n+1; i++)
if (l[i].k!=l[cnt].k) l[++cnt]=l[i];
q[++tail]=l[1]; q[++tail]=l[2];
for (i=3; i<=cnt; i++){
while (head<tail && ok(q[tail-1],q[tail],l[i])) tail--;
while (head<tail && ok(q[head+1],q[head],l[i])) head++;
q[++tail]=l[i];
}
while (head<tail && ok(q[tail-1],q[tail],q[head])) tail--;
while (head<tail && ok(q[head+1],q[head],q[tail])) head++;
cnt=0; for (i=head; i<tail; i++) b[++cnt]=itr(q[i],q[i+1]);
}
int main(){
scanf("%d",&n); int i,j;
for (i=1; i<=n; i++) scanf("%lf",&a[i].x);
for (i=1; i<=n; i++) scanf("%lf",&a[i].y);
a[0].x=a[1].x; a[0].y=1e6;
a[n+1].x=a[n].x; a[n+1].y=1e6;
for (i=0; i<=n; i++){
l[++cnt].p=a[i]; l[cnt].v=a[i+1]-a[i];
l[cnt].k=atan2(l[cnt].v.y,l[cnt].v.x);
}
bpmj(); double ans=1e50;
for (i=1; i<=cnt; i++)
for (j=1; j<n; j++) if (a[j].x<=b[i].x && b[i].x<=a[j+1].x)
ans=min(ans,b[i].y-valx(a[j],a[j+1]-a[j],b[i].x));
for (i=1; i<=n; i++)
for (j=1; j<cnt; j++) if (b[j].x<=a[i].x && a[i].x<=b[j+1].x)
ans=min(ans,valx(b[j],b[j+1]-b[j],a[i].x)-a[i].y);
printf("%.3f\n",ans);
return 0;
}
by lych
2016.3.1