POJ1118 Lining Up
http://poj.org/problem?id=1118
题意
给你n个二维平面点的坐标,问你最多有多少个点共线?
输入
多组输入,先输入整数N ( 1 < N < 700 ),表示有N个点,接下来N行每行一对整数,表示点的坐标。N=0表示结束。
输出
每组对应一个整数输出,表示最多共线的点数。
样例输入
5
1 1
2 2
3 3
9 10
10 11
0
样例输出
3
分析
运用叉积,枚举每条直线,计算在这条直线上的点的数量,不断更新最终答案。我们可以这样实现:
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i!=j)
{
int num=0;//统计在直线 ij 上的点数
for(int k=0;k<n;k++)
{
//运用叉积判断点k是否在直线 ij 上
}
ans=max(ans,num);//更新最终答案
}
但是可以发现,有两个地方可以改进一下:其一,同一条直线会被枚举两次,直线 ij 和直线 ji 是同一条,我们可以对第二个循环进行优化。其二,假设正确答案是4,点1,2,3,4共线,虽然可以保证每条直线只被枚举一次,但是会发现枚举直线 12时会找到3,4;枚举直线23时会找到1,4;...;也就是说,这样花了时间但是不会使答案更新,怎么解决?由于问题只是让我们求共线的点的个数,那么我们可以在第三个循环上进行优化。具体如下:
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)//保证每条直线只被枚举一次
{
int num=2;//点i、j
for(int k=j+1;k<n;k++)//保证了不会出现第二种问题
if(点k在直线ij上) //运用叉积
num++;
ans=max(ans,num);
}
C++程序
#include<iostream>
#include<cmath>
using namespace std;
const int N=705;
const double EPS=1e-8;
struct Point{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
Point operator -(const Point &a)const
{
return Point(x-a.x,y-a.y);
}
double operator ^(const Point &a)const
{
return x*a.y-y*a.x;
}
};
int main()
{
Point p[N];
int n;
while(~scanf("%d",&n)&&n)
{
int ans=0;
for(int i=0;i<n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
int num=2;
for(int k=j+1;k<n;k++)
if(fabs((p[i]-p[k])^(p[j]-p[k]))<EPS)//点k在直线ij上
num++;
ans=max(ans,num);
}
printf("%d\n",ans);
}
return 0;
}