URAL 1207 Median on the Plane(直线分割点集:极角排序)
http://acm.timus.ru/problem.aspx?space=1&num=1207
题意:
给你n个点的点集,任意3点不共线. 要你找出其中两点,使得该两点的连线正好二等分了整个点集.
分析:
只要找到该点集的最左下角的点(优先x坐标最小,如果有多个x坐标最小的点,那就选那个y坐标小的点.不可能两点重合)
找到该点之后,把所有其他点与该点连线,按连线的极角排序即可.最终输出该点和排序后数组的中间那个点即可.
极角排序我们不是直接算极角的,而是用两个向量的叉积的正负来判断到底是第一个向量在左边还是第二个向量在左边. 在左边的向量的端点在数组的前面.
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=10000+5;
const double eps=1e-10;
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
return x<0?-1:1;
}
struct Point
{
double x,y;
int id;
Point(){}
Point(double x,double y,int id):x(x),y(y),id(id){}
}P[maxn];
typedef Point Vector;
Vector operator-(Point A,Point B)
{
return Vector(A.x-B.x,A.y-B.y,0);
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
bool cmp(Point A,Point B)//极角排序比较函数
{
return dcmp(Cross(A-P[0],B-P[0]))<0;
}
int main()
{
int n;
while(scanf("%d",&n)==1)
{
scanf("%lf%lf",&P[0].x,&P[0].y);
P[0].id=1;
for(int i=1;i<n;++i)
{
scanf("%lf%lf",&P[i].x,&P[i].y);
P[i].id=i+1;
if(P[i].x<P[0].x || (P[i].x==P[0].x && P[i].y<P[0].y) )
swap(P[0],P[i]);//将最左下角的点换到0号位置
}
sort(P+1,P+n,cmp);
printf("%d %d\n",P[0].id,P[n/2].id);
}
return 0;
}