Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
简单分析—判断圆心到线段最近距离的方法这道题的算法是先判断每对顶点间能否连接一条线段,然后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: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator