Max Points on a Line

Problem:

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

分析:

初读题目,想到的思路是求每两个点之间的直线,然后判断剩下的点有多少在这条直线上。一共有n(n-1)/2条直线,而判断剩余的点一共有n-1个,所以这样的算法复杂度是O(n^3)。为了降低算法的时间复杂度,改进的点主要是用map存储下来已经做过判断的直线,这样可以快速判断新添加的点落在哪个直线上。题目中的点均是整数点,直线的表示方法最好选一般式,即ax + by + c = 0,这样能够保证a, b, c均是整数,在map中作为键值的时候可以自定义偏序关系。

 1 struct Coef {
 2     int a;
 3     int b;
 4     int c;
 5 
 6     Coef() : a(0), b(0), c(0) {}
 7     Coef(int x, int y, int z) : a(x), b(y), c(z) {}
 8 
 9     friend bool operator<(const Coef &x, const Coef &y)
10     {
11         if(x.a != y.a) {
12             return x.a < y.a;
13         } else if(x.b != y.b) {
14             return x.b < y.b;
15         } else if(x.c != y.c) {
16             return x.c < y.c;
17         } else {
18             return false;
19         }
20     }
21 };
View Code

对于即将要判断的两个点(x1, y1)与(x2, y2),他们的一般式为(y2-y1)x - (x2-x1)y +x2y1-x1y2 = 0(这里姑且取b=x2-x1,前面的符号没有影响)。但还要注意最简形式的约分,要求三个数的最大公约数。例如点(0, 0)、(1, 1)求得 a = 1, b = 1, c = 0,而点(0, 0)、(2, 2)求得a = 2, b = 2, c = 0,这三个点共线,但两个直线方程系数不同是因为后面一组不是最简形式。除此之外有负号的情况也要考虑,比如点(0, 0)、(-1, -1)与上面的两组都共线,但因为有负号也会不同,所以全部应该化为最简形式。

void simpleForm()
{
    int cd = gcd(gcd(a, b), c);
    if(cd > 0) {
        a /= cd;
        b /= cd;
        c /= cd;
    }

    if(a < 0) {
        a *= -1;
        b *= -1;
        c *= -1;
    } else if(a == 0 && b < 0) {
        b *= -1;
        c *= -1;
    } else if(a == 0 && b == 0 && c < 0) {
        c *= -1;
    }
}
View Code

最后需要注意的就是测试的边界条件,比如集合中只有一个点,还有集合中的点有重复。这些边界条件都容易造成WA。完整的代码可以参考下面。

  1 int gcd(int a, int b)
  2 {
  3     if(a < 0)
  4         a *= -1;
  5     if(b < 0)
  6         b *= -1;
  7 
  8     if(a < b) {
  9         swap(a, b);
 10     } 
 11 
 12     while(b != 0) {
 13         int r = a % b;
 14         a = b;
 15         b = r;
 16     }
 17     return a;
 18 }
 19 
 20 struct Coef {
 21     int a;
 22     int b;
 23     int c;
 24 
 25     Coef() : a(0), b(0), c(0) {}
 26     Coef(int x, int y, int z) : a(x), b(y), c(z) {}
 27 
 28     void simpleForm()
 29     {
 30         int cd = gcd(gcd(a, b), c);
 31         if(cd > 0) {
 32             a /= cd;
 33             b /= cd;
 34             c /= cd;
 35         }
 36 
 37         if(a < 0) {
 38             a *= -1;
 39             b *= -1;
 40             c *= -1;
 41         } else if(a == 0 && b < 0) {
 42             b *= -1;
 43             c *= -1;
 44         } else if(a == 0 && b == 0 && c < 0) {
 45             c *= -1;
 46         }
 47     }
 48 
 49     friend bool operator<(const Coef &x, const Coef &y)
 50     {
 51         if(x.a != y.a) {
 52             return x.a < y.a;
 53         } else if(x.b != y.b) {
 54             return x.b < y.b;
 55         } else if(x.c != y.c) {
 56             return x.c < y.c;
 57         } else {
 58             return false;
 59         }
 60     }
 61 };
 62 
 63 class Solution {
 64 public:
 65     int maxPoints(vector<Point> &points) {
 66         if(points.size() <= 2)
 67             return points.size();
 68         
 69         int maxPoint = 0;
 70         for(int i = 0; i < points.size(); ++i) {
 71             int sameCounts = 0;
 72             map<Coef, int> counts;
 73             for(int j = i+1; j < points.size(); ++j) {
 74                 Point p1 = points[i];
 75                 Point p2 = points[j];
 76 
 77                 if(p1.x == p2.x && p1.y == p2.y) {
 78                     ++sameCounts;
 79                     continue;
 80                 }
 81 
 82                 int a = p2.y - p1.y;
 83                 int b = p2.x - p1.x;
 84                 int c = p2.x * p1.y - p1.x * p2.y;
 85                 
 86                 Coef coef(a, b, c);
 87                 coef.simpleForm();
 88 
 89                 if(counts.find(coef) == counts.end()) {
 90                     counts[coef] = 1;
 91                 } else {
 92                     ++counts[coef];
 93                 }
 94             }
 95 
 96             int curMax = 0;
 97             map<Coef, int>::iterator it = counts.begin();
 98             for(; it != counts.end(); ++it) {
 99                 if(it->second > curMax)
100                     curMax = it->second;
101             }
102             
103             if(sameCounts + curMax + 1> maxPoint)
104                 maxPoint = sameCounts + curMax + 1;
105         }
106 
107         return maxPoint;
108     }
109 };

 

 

posted @ 2014-04-27 17:03  夏目家的猫咪老师  阅读(180)  评论(0编辑  收藏  举报