Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

简单分析—判断圆心到线段最近距离的方法

Posted by Ever_ljq at 2012-01-11 18:23:12 on Problem 3178 and last updated at 2012-01-11 18:29:23
这道题的算法是先判断每对顶点间能否连接一条线段,然后DP。另外,不用对输入的点排序(本身就是有序的了)。
DP并不是很难,所以关键在于如何判断任意点对间能否连接一条线段。
显然,我们只需要枚举所有的圆,然后判断圆心到线段的距离是否大于半径就行了。

如何计算圆心到线段的距离呢?设A, B为线段的两个端点,C为圆心。
如果△ABC是以AC或BC为最长边的钝角三角形,则C到线段AB的距离为min{AC, AB}。
否则C到线段AB的距离等于C到直线AB的距离。
(读者可以画画图想象一下)

首先,如何判断△ABC的形状呢?我们可以使用高中学过的余弦定理。
△ABC为以AC为最长边的钝角三角形<=>|AC|^2>|AB|^2+|BC|^2.

接下来只需要处理第二种情况了。当然我们使用解析几何的办法,然而这不是很优美。我们可以用简单的叉积解决这个问题。
因为△ABC的面积S等于向量AB和向量AC的叉积的绝对值的一半,所以只需要做下AB和AC的叉积再除以|AB|就可以得到这个距离了。
不过为了避免可能的精度问题,我们可以把要算的这些数平方,直接比较平方的大小。

以下是这个过程的C++参考代码:

typedef long long LL;

struct Tpoint{
	int x, y;
} Cs[maxn], Ps[maxn];//Cs存储圆心坐标,Ps存储多边形顶点的坐标

LL cross(Tpoint p1, Tpoint p2)//计算叉积
{
	return (LL)p1.x * p2.y - (LL)p2.x * p1.y;
}

LL dis2(Tpoint a, Tpoint b)//计算两个点距离的平方
{
	return ((LL)a.x - b.x) * (a.x - b.x) + ((LL)a.y - b.y) * (a.y - b.y);
}


bool check(int u, int v, int t)//返回线段uv是否不经过圆t
{
	LL j = dis2(Ps[u], Cs[t]), k = dis2(Ps[v], Cs[t]), l = dis2(Ps[u], Ps[v]);	//分别是三角形三条边的长度的平方
	if (j <= r2) return 0;//点u在圆内, r2是半径的平方
	if (k <= r2) return 0;	
	Tpoint p1 = Ps[u], p2 = Ps[v];
	p1.x -= Cs[t].x; p1.y -= Cs[t].y;
	p2.x -= Cs[t].x; p2.y -= Cs[t].y;//p1, p2分别为向量tu和向量tv
	LL a = cross(p1, p2);//a为三角形面积二倍的平方
	if ((double)a * a > (double)r2 * l) return 1;//不等式变形后判断距离是否比半径大,使用double防止越界
	if (j + l > k && k + l > j) return 0;//第一种情况且两个顶点都在圆外
	return 1;
}

Followed by:

Post your reply here:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator