POJ1118 Lining Up【判断共线】

                                      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;
}

 

猜你喜欢

转载自blog.csdn.net/SongBai1997/article/details/85028261
今日推荐