题面
给出 n (1<=n<=700) 个点,问最多多少个点共线
分析
先把多点共线变成三点共线问题,即取两个定点,判断第三个动点是否与这两个定点共线,动点遍历完所有后,再改变定点。如此能得到一个 O(n3) 的方法(实际上能跑过这个题,因为一方面 Cn2C_{n}^{2}Cn2 其实近似 n2/2 ,另一方面题的数据量貌似比 700 要小)
如果能解决三点共线问题,就能解决这个多次判定三点共线问题
判断三点共线有较多的做法,比较普遍的有两种:
浮点型:算以一点出发到两点的斜率,判定其是否相等即可,一般要考虑误差,而且可能有斜率不存在情况
向量型:两个向量 (x1,y1)(x_1 , y_1)(x1,y1) 和 (x2,y2)(x_2 , y_2)(x2,y2) 共线当且仅当 x1y2=x2y1x_1y_2=x_2y_1x1y2=x2y1
本题的输入都是整数,所以用向量型更优。
算法也就如下:
1.取定两个点 i , j .
2.从 i 连接另外一个动点 k , 判定 ij 与 ik 是否共线,如果共线则共线点+1
3.回到1步,且改变取定的点
代码
#include "cstdlib"
#include <iostream>
#include<algorithm>
#include<string.h>
#include<string>
using namespace std;
int x[705], y[705];
int main()
{
ios::sync_with_stdio(false);
int n;
cin >> n;
for (register int i = 0; i < n; i++)cin >> x[i] >> y[i];
int ans = 0;//保存两个定点下的共线点最大值
int temp = 0;//保存当前两个定点下的共线点有多少个
int v1x, v1y;//vector1:x,y,用定点构造
for (register int i = 0; i < n; i++)
{
for (register int j = i+1; j < n; j++)//(i,j)是取的定点,有C(2,n)种取法
{
temp = 0;
v1x = x[i] - x[j];
v1y = y[i] - y[j];
for (int k = 0; k < n; k++)//k是第三个动点,ik和ij两条直线共线则temp++;
{
if (v1x * (y[i] - y[k]) == v1y * (x[i] - x[k]))temp++;
}
ans = max(temp, ans);
}
}
cout << ans;
return 0;
}