今天在面经中看到的一道手写代码题,题意是在一个二维平面内,有n个点(n < 700),让你在平面内找到一条直线,使得最多的点落在这条直线上,问最多能落在你找的这条直线上的点数是多少,原题是POJ 1118
先不去考虑细节,只从大方向上考虑,这个题的思路是:
我们先选取一个点作为基准点,然后计算其余点和这个基准点构成的直线的斜率(如果有两个点和这个基准点构成的直线的斜率是相同的,那么这三个点是共线的)
这n-1个斜率都计算完成后,将他们排序,然后从左到右扫一遍,看每种斜率有多少个,数量最多的那种斜率的数量+1就是以这个点为基准点的时候最多能够共线的点的数目
再依次把剩下的点作为基准点,重复上述操作,所有基准点对应的最多能够共线的点的数目的最大值就是答案
接下来我们来考虑一下实现细节:
1. 这个题涉及到斜率计算,必须要注意有的情况斜率是不存在的,所以当两个点的横坐标相等时,我们需要特殊处理,而不能去计算斜率
2. 斜率是一个double类型的数据,统计数目时不能用木桶,只能排序之后从左到右扫一遍去数每种斜率的数目(在数的时候记得要把当前斜率是否和上一个斜率相等的条件改成两者的差的绝对值<1e-6,而不是写个==)
3. 在具体实现过程中,我用一个pair<bool, double>来记录斜率,pair中的bool变量用来记录这个斜率是否存在,如果存在斜率(pair中的bool变量取值为true),pair中的double变量记录斜率;如果斜率不存在(pair中的bool变量取值为false),pair中的double变量记录基准点的横坐标(既然斜率不存在,那么这个点必定是横坐标和基准点的横坐标是相同的)
4. 由于使用了一个pair来记录斜率,因此需要重新定义一下比较函数:
①我们规定不存在斜率的pair比所有存在斜率的pair都小,即当我们比较一个有斜率的pair和一个没有斜率的pair的时候,没有斜率的pair<有斜率的pair
②两个有斜率的pair,比较他们的斜率大小
③两个没有斜率的pair,比较他们的X坐标的大小
代码如下:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef pair<bool, double> pdd; const int N = 800; int arrX[N]; //存放所有点的横坐标 int arrY[N]; //存放所有点的纵坐标 int cmp(const pdd& a, const pdd& b) { if(!a.first && b.first) return true; //a是false,b是true,返回true(a比b小) if(a.first && !b.first) return false; //a是true,b是false,返回false(a比b大) return a.second < b.second; } int main() { int n; cin >> n; while(n) { for(int i = 0; i < n ;i++) { scanf("%d%d", &arrX[i], &arrY[i]); //读入横纵坐标 } int result = -1; for(int i = 0; i < n; i++) { pdd arr[N]; //定义一个pair数组 int cnt = 0; //记录pair的数量 for(int j = 0; j < n; j++) { if(j == i) continue; if(arrX[i] == arrX[j]) { //没有斜率 arr[cnt].first = false; arr[cnt++].second = arrX[i]; //没有斜率则记录横坐标X值 } else { //有斜率 double k = 1.0 * (arrY[i] - arrY[j]) / (arrX[i] - arrX[j]); arr[cnt].first = true; arr[cnt++].second = k; //有斜率则记录斜率 } } sort(arr, arr+cnt, cmp); //排序 //从左到右扫一遍,找出数量最多的斜率的数量 pdd now = make_pair(false, 1000000000000000); int nowCount = 0, maxCount = -1; for(int j = 0; j < cnt; j++) { if(arr[j].first == now.first && fabs(arr[j].second - now.second) < 1e-6) { //这个斜率和上一个斜率相等 nowCount++; } else { //这个斜率和上一个斜率不等 maxCount = max(maxCount, nowCount); now = arr[j]; nowCount = 1; } } maxCount = max(maxCount, nowCount); //最后一个斜率的数量没有被结算,需要手动结算一下 result = max(result, maxCount); } cout << result+1 << endl; //结果需要+1 cin >> n ; } return 0; }