ZOJ 3762 Pan's Labyrinth (點集中的最大點-線距&技巧性枚舉)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3762


思路:(轉自這篇文章
先討論銳角/直角三角形的情況:

假設擁有最大高的三角形是ABC,如下圖

結合此圖我們可以看出最大高是點C到直線AB,在這種情況下,下列兩個結論至少有一個成立

1.點C是所有點中距離點A最遠的

2.點C是所有點中距離點B最遠的

反證:(這裏先證明在AB上側成立的情況)

首先過點C做直線A'B'平行於AB,再分別以點A、點B爲圓心,AC、BC長爲半徑做圓

假設點C對上述兩條結論均不成立,則還有一異於點C的點D至少滿足上述兩條結論之一,那麼點D只能在直線A'B'以上且在圓A、B外的區域內。

顯然,點D到直線AB的距離>點C到直線的距離,即△DAB的最大高>△CAB的最大高,與前提“擁有最大高的三角形是ABC”矛盾。

得證。

而在AB下側,那兩個圓的交點和點C是關於AB對稱的,道理也一樣,就不贅述了。

所以在△ABC是銳角/直角三角形時,“找最遠點”的策略一定是對的。

再看看鈍角三角形的情況:

這種情況發生在當點D位於點C的右下方,且在兩個圓外面時。

這時△ACD的最大高>△ACB的最大高(可以畫畫輔助線對比下)

所以△ABC是鈍角三角形時,“找最遠點”的策略亦是對的。

因此我們可以對每個點,先O(n)枚舉距離它最遠的點,再O(n)枚舉三角形的另一個點就可以了,整體複雜度爲O(n^2)。

完整代碼:

/*510ms,176KB*/

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

struct P
{
	double x, y;
} p[505];

///求pp到直線ab的距離
double dis(P &a, P &b, P &pp)
{
	if (b.x != a.x)
	{
		double k = (b.y - a.y) / (b.x - a.x); ///直線斜率
		return fabs((pp.y - a.y) - k * (pp.x - a.x)) / sqrt(1 + k * k); ///套公式
	}
	return fabs(pp.x - a.x);
}

int main()
{
	int n, i, j, maxp;
	double maxdis, tmp, ans;
	while (~scanf("%d", &n))
	{
		ans = 0;
		for (i = 0; i < n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
		for (i = 0; i < n; i++)
		{
			maxdis = 0;
			for (j = 0; j < n; j++)
			{
				if (i == j) continue;
				tmp = hypot(p[i].x - p[j].x, p[i].y - p[j].y);
				if (tmp > maxdis) maxdis = tmp, maxp = j;
			}
			for (j = 0; j < n; j++)
			{
				if (j == i || j == maxp) continue;
				ans = max(dis(p[i], p[j], p[maxp]), ans);
				//ans = max(dis(p[i], p[maxp], p[j]), ans); ///由於i-pmax這條邊一定不是最短邊,故垂足一定不在這條直線上
				ans = max(dis(p[maxp], p[j], p[i]), ans); /// 最大高
			}
		}
		printf("%f\n", ans);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章