计算几何 之 hdu 1077 poj 1981 O(n^2logn)

花了很长时间,终于理解了一些。。。

注意两题输入格式不同。。。O(n^2logn) 

有另一种非常好理解一些的算法,不过时间差点O(n^3),亦能AC  详解+代码,请点击这里 

 

//  [7/10/2014 Sjm]
// 题目: 用半径为 1 的圆,尽可能多的包含所给点。
 
/***********************************************************************
其实要理解时间复杂度为O(n^2lgn)的算法,首先要知道以下三点:
1)若以一个点 p 为圆心,在半径为 1 的圆内,随便选一个点 p1,皆可捕获到点 p
2)此时,我们把所给的点皆作为圆心,皆做半径为 1 的圆,
3)在圆的交集中,所重叠的最高层数,即:所要求的答案。。。
************************************************************************/
/*
根据以上三点作为基础,理解网上的时间复杂度为O(n^2lgn)的算法,便比较容易了。。
 
关键:将圆的重叠部分转换为弧的重叠部分。(这里可以自己画几个图理解一下)
 
遍历每一个点
	以此点 p 做半径为 1 的圆C,可以获得此圆C与以其他点为圆心所作圆Ci的相交弧(即圆C被圆Ci截取的那段弧),
	存储该相交弧的起点以及终点的极角(并区分它们)到数组;
	对此数组进行排序(若极角相等,端点:始点-->终点;否则,极角:小-->大)
	此时遍历此数组
		1)如果遇到起点,则sum++,表示此时弧可以有重叠 => 可以覆盖到数组此时所代表的点
		在此过程中,若sum > ans, 则 ans = aum (ans 代表所要获得的答案)
		2)如果遇到终点,则sum--,表示此弧已无法重叠 => 已覆盖不到数组此时所代表的点
遍历结束,获得答案。   
 
*/
 1 //hdu 1077
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstdio>
 5 #include <cmath>
 6 #include <algorithm>
 7 using namespace std;
 8 const int MAX = 305;
 9 const double eps = 1e-6;
10 int N;
11 double arr_p[MAX][2];
12 
13 double Angle[MAX][2];
14 
15 struct Angle_Jug {
16     double angle; // 记录极角
17     bool Judge;  // 判断方向:true->相交弧的起点,false->相交弧的终点
18 };
19 };
20 
21 Angle_Jug Aj[MAX];
22 
23 double Distance(int p1, int p2)
24 {
25     return sqrt((arr_p[p2][0] - arr_p[p1][0])*(arr_p[p2][0] - arr_p[p1][0]) +
26         (arr_p[p2][1] - arr_p[p1][1])*(arr_p[p2][1] - arr_p[p1][1]));
27 }
28 
29 bool Cmp(const Angle_Jug &ag1, const Angle_Jug &ag2) {
30     if (ag1.angle == ag2.angle) {
31         return (ag1.Judge > ag2.Judge);
32     }
33     return ag1.angle < ag2.angle;
34 }
35 
36 int Solve(double R) {
37     int ans = 1;
38     for (int i = 0; i < N; i++) {
39         int m = 0;
40         for (int j = 0; j < N; j++) {
41             double dis = Distance(i, j);
42             if ((i == j) || (dis > 2 * R)) { continue; }
43             double tep = acos((dis / 2.0) / R);
44             double k = atan2(arr_p[j][1] - arr_p[i][1], arr_p[j][0] - arr_p[i][0]);
45             Aj[m].angle = k - tep;  Aj[m++].Judge = true;
46             Aj[m].angle = k + tep;  Aj[m++].Judge = false;
47         }
48         sort(Aj, Aj + m, Cmp);
49         int sum = 1;
50         for (int k = 0; k < m; k++) {
51             if (Aj[k].Judge)  {
52                 sum++;
53                 ans = (ans > sum) ? ans : sum;
54             }
55             else { sum--; }
56         }
57     }
58     return ans;
59 }
60 
61 int main()
62 {
63     //freopen("input.txt", "r", stdin);
64     int T;
65     scanf("%d", &T);
66     while (T--) {
67         scanf("%d", &N);
68         for (int i = 0; i < N; i++) {
69             scanf("%lf %lf", &arr_p[i][0], &arr_p[i][1]);
70         }
71         printf("%d\n", Solve(1.0));
72     }
73 }

 

 

 1 //poj 1981
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstdio>
 5 #include <cmath>
 6 #include <algorithm>
 7 using namespace std;
 8 const int MAX = 305;
 9 const double eps = 1e-6;
10 int N;
11 double arr_p[MAX][2];
12 
13 double Angle[MAX][2];
14 
15 struct Angle_Jug {
16     double angle; // 记录极角
17     bool Judge;  // 判断方向:true->相交弧的起点,false->相交弧的终点
18 };
19 
20 Angle_Jug Aj[MAX];
21 
22 double Distance(int p1, int p2)
23 {
24     return sqrt((arr_p[p2][0] - arr_p[p1][0])*(arr_p[p2][0] - arr_p[p1][0]) +
25         (arr_p[p2][1] - arr_p[p1][1])*(arr_p[p2][1] - arr_p[p1][1]));
26 }
27 
28 bool Cmp(const Angle_Jug &ag1, const Angle_Jug &ag2) {
29     if (ag1.angle == ag2.angle) {
30         return (ag1.Judge > ag2.Judge);
31     }
32     return ag1.angle < ag2.angle;
33 }
34 
35 int Solve(double R) {
36     int ans = 1;
37     for (int i = 0; i < N; i++) {
38         int m = 0;
39         for (int j = 0; j < N; j++) {
40             double dis = Distance(i, j);
41             if ((i == j) || (dis > 2 * R)) { continue; }
42             double tep = acos((dis / 2.0) / R);
43             double k = atan2(arr_p[j][1] - arr_p[i][1], arr_p[j][0] - arr_p[i][0]);
44             Aj[m].angle = k - tep;  Aj[m++].Judge = true;
45             Aj[m].angle = k + tep;  Aj[m++].Judge = false;
46         }
47         sort(Aj, Aj + m, Cmp);
48         int sum = 1;
49         for (int k = 0; k < m; k++) {
50             if (Aj[k].Judge)  {
51                 sum++;
52                 ans = (ans > sum) ? ans : sum;
53             }
54             else { sum--; }
55         }
56     }
57     return ans;
58 }
59 
60 int main()
61 {
62     //freopen("input.txt", "r", stdin);
63     while (scanf("%d", &N) && N) {
64         for (int i = 0; i < N; i++) {
65             scanf("%lf %lf", &arr_p[i][0], &arr_p[i][1]);
66         }
67         printf("%d\n", Solve(1.0));
68     }
69     return 0;
70 }

 


 

转载于:https://www.cnblogs.com/shijianming/p/4140836.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值