BZOJ 1038 ZJOI2008 瞭望塔 模拟退火+二分答案

31 篇文章 0 订阅
2 篇文章 0 订阅

题目大意:给定一条折线,要求选择一个点建立高度为h的瞭望塔,要求瞭望塔塔顶可以看到折线上的每一个点,求h的最小值

正解:半平面交

不会!

于是我们选择模拟退火来寻找瞭望塔的横坐标

确定瞭望塔的高度的时候我们选择二分处理 对于二分的每一个值 我们把折线上的端点从左到右枚举 瞭望塔的塔尖到每个端点的连线必须从左到右逆时针顺序 否则就会被遮挡


如图,塔尖到点2的连线在到点1的连线的顺时针方向,故点1被遮挡,该高度不可行

写完交上去各种秒WA,最后发现我的INF又不够大。。。我沙茶,我蒟蒻,我这个不长记性的大二货0.0

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 310
using namespace std;
struct point{
	double x,y;
	point(){}
	point(double X,double Y)
	{
		x=X;
		y=Y;
	}
}points[M];
point operator - (const point &x,const point &y)
{
	return point(x.x-y.x,x.y-y.y);
}
double operator * (const point &x,const point &y)
{
	return x.x*y.y-y.x*x.y;
}
struct line{
	point *p1,*p2;
	double k,b;
	void get_function()
	{
		point p=(*p2)-(*p1);
		k=(double)p.y/p.x;
		b=p1->y-k*p1->x;
	}
	double f(double x)
	{
		return k*x+b;
	}
}lines[M];
int n;
double ans,ansheight=1e11;
double Rand()
{
	return rand()%1000/1000.0;
}
bool Judge(point p)
{
	int i;
	for(i=2;i<=n;i++)
	{
		if( (points[i-1]-p)*(points[i]-p)<0 )
			return false;
	}
	return true;
}
double f(double x)
{
	int i;
	for(i=2;i<=n;i++)
		if( x>=lines[i].p1->x && x<=lines[i].p2->x )
			return lines[i].f(x);
}
double Divide(double x)
{
	double l=0,r=1e11;
	double mid=(l+r)/2;
	while(r-l>1e-7)
	{
		if( Judge( point(x,mid) ) )
			r=mid;
		else
			l=mid;
		mid=(l+r)/2;
	}
	mid-=f(x);
	if(mid<ansheight)
		ans=x,ansheight=mid;
	return mid;
}
void SA(double T)
{
	int i;
	double Now=ans;
	for(;T>0.00001;T*=0.99)
	{
		double Neo=Now+T*(Rand()*2-1);
		if( Neo<points[1].x || Neo>points[n].x )
			continue;
		double dE = Divide(Now) - Divide(Neo);
		if( dE>0 || exp(dE/T)>Rand() )
			Now=Neo;
	}
	for(i=1;i<=1000;i++)
	{
		double Neo=ans+T*(Rand()*2-1);
		if( Neo<points[1].x || Neo>points[n].x )
			continue;
		Divide(Neo);
	}
}
int main()
{
	srand(19980406);
	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=2;i<=n;i++)
		lines[i].p1=&points[i-1],lines[i].p2=&points[i],lines[i].get_function();
	ans=(points[n].x+points[1].x)/2.0;
	SA( points[n].x-points[1].x );
	printf("%.3lf\n",ansheight+1e-7);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值