UVa 11168 Airport

本文介绍了一道计算几何题目,目标是找到一条直线使所有给定点位于直线同一侧且距离和最小。通过构建这些点的凸包并遍历其边来寻找最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个月看看计算几何,这道题写的代码出现的问题还是挺多的,不过索性最后解决了。

题意:给出平面上n个点,找一条直线,使得所有点在直线的同侧(也可以在直线上),且到直线上的距离之和尽量小。

思路:计算几何凸包求出包含所有点的多边形,那么所求直线即多边形其中一条边,这里涉及一个优化除该边之外所有点到边的距离,因为所有点在直线一侧,求出所有点的x坐标之和还有y坐标之和,用一般式解决,算法时间O(1),接下来就是遍历所有边了算法时间O(n).

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define INF 0x3f3f3f3f
struct Point
{
  double x,y;
  Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector ;
Vector operator + (const Vector& a, const Vector& b) {
    return Vector(a.x+b.x, a.y+b.y);
}
Vector operator - (const Vector& a, const Vector& b) {
    return Vector(a.x-b.x, a.y-b.y);
}
Vector operator * (const Vector& a, double p) {
    return Vector(a.x*p, a.y*p);
}
Vector operator / (const Vector& a, double p) {
    return Vector(a.x/p, a.y/p);
}
bool operator < (const Point& p1, const Point& p2){
    return p1.x<p2.x ||(p1.x==p2.x&&p1.y<p2.y);
}
bool operator == (const Point& p1, const Point& p2){
    return p1.x == p2.x && p1.y == p2.y;
}
double Cross(Vector A,Vector B) { return A.x*B.y - A.y*B.x;}
Point GLI(Point P,Vector v,Point Q,Vector w)
{
  Vector u=P-Q;
  double t=Cross(w,u)/Cross(v,w);
  return P+v*t;
}

int Andrew(Point *p,int n,Point *q)
{
  sort(p,p+n);
  int m=0;
  for(int i=0;i<n;i++)
  {
    while(m>1&&Cross(q[m-1]-q[m-2],p[i]-q[m-2])<=0) m--;
    q[m++]=p[i];
  }
  int k=m;
  for(int i=n-2;i>=0;i--)
  {
    while(m>k&&Cross(q[m-1]-q[m-2],p[i]-q[m-2])<=0) m--;
    q[m++]=p[i];
  }
  if(n>1) m--;
  return m;
}
const int maxn=10005;
Point q[maxn];
int main()
{
  int T,n,Case=1;double x,y;
  cin>>T;
  while(T--)
  {
    cin>>n;Point p[maxn];
    double xx=0,yy=0;
    for(int i=0;i<n;i++)
    {
      cin>>x>>y;
      p[i].x=x;p[i].y=y;
      xx+=x;yy+=y;
    }
    int m=Andrew(p,n,q);
    q[m]=q[0];
    /*for(int i=0;i<m;i++)
    {
      printf("^%f %f\n",q[i].x,q[i].y);
    }*/
    double ans=INF;
    //printf("#%f %f\n",xx,yy);
    for(int i=0;i<m;i++)
    {
      //i=(i+1)%m;
      //int x0=(xx-q[i].x-q[i+1].x);
      //int y0=(yy-q[i].y-q[i+1].y);
      double A=(q[i].y-q[i+1].y);
      double B=q[i+1].x-q[i].x;
      double C=(q[i+1].y*q[i].x-q[i].y*q[i+1].x);
      //printf("%f,%f,%f\n",A,B,C);
      ans=min(ans,fabs(A*xx+B*yy+C*n)/sqrt(A*A+B*B));
    }
    printf("Case #%d: ",Case++);
    if(n<=2) printf("0.000\n");
    else
    printf("%.3f\n",ans/n);
    //Q.erase();
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值