首页 > 代码库 > BZOJ 1038 ZJOI2008 瞭望塔 半平面交

BZOJ 1038 ZJOI2008 瞭望塔 半平面交

题目大意及模拟退火题解:见 http://blog.csdn.net/popoqqq/article/details/39340759 

这次用半平面交写了一遍……求出半平面交之后,枚举原图和半平面交的每个点,求出答案即可

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 310
#define eps 1e-7
using namespace std;
struct point{
	double x,y;
}points[M];
struct line{
	point *p1,*p2;
	double k,b;
	void Get_Parameters()
	{
		k=(double)(p1->y-p2->y)/(p1->x-p2->x);
		b=p1->y-k*p1->x;
	}
	bool operator < (const line &x) const
	{
		if( fabs(k-x.k)<eps )
			return b < x.b;
		return k < x.k;
	}
}lines[M];
int n;
double ans=1e11;
line *stack[M];int top;
inline point Get_Intersection(const line &l1,const line &l2)
{
	point re;
	re.x=-(l1.b-l2.b)/(l1.k-l2.k);
	re.y=l1.k*re.x+l1.b;
	return re;
}
void Insert(line &l)
{
	while(top>=2)
	{
		if( Get_Intersection(*stack[top],l).x < Get_Intersection(*stack[top-1],*stack[top]).x )
			--top;
		else
			break;
	}
	stack[++top]=&l;
}
double F(double x)
{
	int i;
	double re=0;
	for(i=1;i<=top;i++)
		re=max(re,stack[i]->k*x+stack[i]->b);
	return re;
}
double G(double x)
{
	int i;
	for(i=n;i;i--)
		if(x>=points[i].x)
			break;
	return points[i].y+(x-points[i].x)/(points[i+1].x-points[i].x)*(points[i+1].y-points[i].y);
}
int main()
{
	int i;
	cin>>n;
	for(i=1;i<=n;i++)
		scanf("%lf",&points[i].x);
	for(i=1;i<=n;i++)
		scanf("%lf",&points[i].y);
	for(i=1;i<n;i++)
		lines[i].p1=points+i,lines[i].p2=points+i+1,lines[i].Get_Parameters();
	sort(lines+1,lines+n);
	for(i=1;i<n;i++)
		if(i==n-1||fabs(lines[i].k-lines[i+1].k)>eps)
			Insert(lines[i]);
	for(i=1;i<=n;i++)
		ans=min(ans,F(points[i].x)-points[i].y);
	for(i=1;i<top;i++)
	{
		point p=Get_Intersection(*stack[i],*stack[i+1]);
		ans=min(ans,p.y-G(p.x));
	}
	printf("%.3lf\n",ans);
}



BZOJ 1038 ZJOI2008 瞭望塔 半平面交