花了很长时间,终于理解了一些。。。
注意两题输入格式不同。。。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 ", 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 ", Solve(1.0)); 68 } 69 return 0; 70 }