HDU 4454 杭州赛区现场赛B题

就是三分~囧~现场赛时把三分的下界写错了一直到最后也没过~另外还把切点都求错了~没救了没救了~刚才看到终于把题挂出来速度去重写~然后1Y~啧啧啧~

做法就是求蚂蚁所在的点与圆形成的两个切线,两个切点把圆绵分成两部分,则蚂蚁爬到圆上的那一点一定在 圆心角<PI 的那一半圆弧上【下图红色部分】:


在红色圆弧上取一个点求点到起点的距离和点到矩形的距离和,则在这段圆弧上的距离和一定是凹函数,我是选择三分角度求圆弧上的点。

当天现场赛结束时芒果神给我说了一个三分矩形上的点然后二分的方法~苣蒻表示没听懂QAQ

现场没能写出这题各种悲剧QAQ滚来滚去滚来滚去

另外现场赛好多人用枚举角度过了这个题QAQ不科学QAQ【扔桌子~摔

刚才膜拜到另一种三分方法,把圆周分成两部分(0,PI)和(PI,2*PI)然后分别三分,这样就不用求切点了QAQ【2012/11/08 20:20】

刚才和别人讨论了一下这题的证明,忽然觉得好麻烦【虽然证出来了】…我当时是靠直觉【2013年6月12日23:04:49】

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <stack>
using namespace std;
#define PI acos(-1)
#define INF 1<<30
#define EPS 1e-6
#define SET(a,b) memset(a,b,sizeof(a))
#define N 10010
#define M 10010
struct point
{
	double x,y;
	int init(){scanf("%lf %lf",&x,&y);}
}cir,p[5],a,o,q1,q2;
double r,th1,th2;
inline double xmult(point p0,point p1,point p2)
{
	return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
point rotate(point p,double angle)
{
	point res;
	res.x=p.x*cos(angle)-p.y*sin(angle);
	res.y=p.x*sin(angle)+p.y*cos(angle);
	return res;
}
void TPC(point poi,point o,double r,point &r1,point &r2)
{
	double line=sqrt((poi.x-o.x)*(poi.x-o.x)+(poi.y-o.y)*(poi.y-o.y));
	double angle=acos(r/line);
	point unit,lin;
	lin.x=poi.x-o.x;
	lin.y=poi.y-o.y;
	unit.x=lin.x/sqrt(lin.x*lin.x+lin.y*lin.y)*r;
	unit.y=lin.y/sqrt(lin.x*lin.x+lin.y*lin.y)*r;
	r1=rotate(unit,-angle);
	r2=rotate(unit,angle);
	r1.x+=o.x; r1.y+=o.y;
	r2.x+=o.x; r2.y+=o.y;
}
double dist(point a,point b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
point intersect(point u1,point u2,point v1,point v2)
{
	double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))
			/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
	point ret=u1;
	ret.x+=(u2.x-u1.x)*t;
	ret.y+=(u2.y-u1.y)*t;
	return ret;
}
double ptoseg(point p,point l1,point l2)
{
	point t=p;
	t.x+=l1.y-l2.y;
	t.y+=l2.x-l1.x;
	if(xmult(p,l1,t)*xmult(p,l2,t)>EPS)
		return min(dist(p,l1),dist(p,l2));
	return dist(intersect(p,t,l1,l2),p);
}
double ddd(double angle)
{
	point ret;
	ret.x=cir.x+r*cos(angle);
	ret.y=cir.y+r*sin(angle);
	double ans=1e100;
	for(int i=0;i<4;i++)
		ans=min(ans,ptoseg(ret,p[i],p[i+1]));
	return dist(ret,a)+ans;
}
void sf(double l,double r)
{
	double m1,m2;
	while (fabs(r-l)>EPS)
	{
		m1=l+(r-l)/3;
		m2=l+(r-l)/3*2;
		if(ddd(m1)<ddd(m2)) r=m2;
		else l=m1;
	}
	printf("%.2lf\n",ddd(l));
}
int main()
{
	while (a.init())
	{
		if(a.x==0 && a.y==0) break;
		cir.init(); scanf("%lf",&r);
		p[0].init(); p[2].init();
		p[1].x=p[2].x; p[1].y=p[0].y;
		p[3].x=p[0].x; p[3].y=p[2].y;
		p[4]=p[0];
		TPC(a,cir,r,q1,q2);
		th1=atan2(q1.y-cir.y,q1.x-cir.x);
		th2=atan2(q2.y-cir.y,q2.x-cir.x);
		if(th1<0) th1+=2*PI;
		if(th2<0) th2+=2*PI;
		if(th1>th2) swap(th1,th2);
		if(th2-th1<PI) sf(th1,th2);
		else sf(th2-2*PI,th1);
	}
	
	return 0;
}










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值