bzoj1038 瞭望塔 半平面交

       首先对于给定的折线求出可行区域的半平面交,可行区域指所有的点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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值