Airport(凸包加点与直线的距离)


题目传送门 : 点击打开链接


题意: 给出平面上的n个点,找出一条直线,使得所有的点都在直线的同一侧或者在直线上,且所有的点到直线的距离最小.


意解: 要求点在线的同一侧,则直线不能够穿过凸包,而且线在凸包的边上时能达到最优解,至于为什么凸包能保证最优解,自己画画图就明白了.

         预处理x,y,然后直接套凸包模板就行了,不过要注意只有一个点的情况,因为这个wa了几次了;


Ac代码:


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define exp 1e-10

using namespace std;
int sumx,sumy;

struct Point
{
    double x,y;
    Point(double x0 = 0, double y0 = 0)
    {
        x = x0;
        y = y0;
    }
    bool operator < (const Point &ant) const
    {
        if(ant.x != x) return ant.x > x;
        return ant.y > y;
    }
};

Point operator - (Point A, Point B)
{
    return Point(A.x - B.x , A.y - B.y);
}

double cross(Point A,Point B)
{
    return A.x * B.y - A.y * B.x;
}

double dcmp(double x)
{
    return x >= 0? x : -x;
}

class Convex
{
public:
    int convex(Point *p, int n, Point *ch)
    {
        int m = 0;
        //sort(p, p + n);
        for(int i = 0; i < n; i++)
        {
            while(m > 1 && cross(ch[m - 1] - ch[m - 2],p[i] - ch[m - 2]) <= exp) m--;
            ch[m++] = p[i];
        }
        int k = m;
        for(int i = n - 2; i >= 0; i--)
        {
            while(m > k && cross(ch[m - 1] - ch[m - 2],p[i] - ch[m - 2]) <= exp) m--;
            ch[m++] = p[i];
        }
        if(n > 1) m--;
        return m;
    }
} hull;

int main()
{
    //freopen("in.txt","r",stdin);
    int T,n,cnt = 0;
    scanf("%d",&T);
    while(T--)
    {
        Point p[11000],ch[11000];
        sumx = sumy = 0;
        printf("Case #%d: ",++cnt);
        scanf("%d",&n);
        for(int i = 0; i < n; i++)
        {
            scanf("%lf %lf",&p[i].x,&p[i].y);
            sumx += p[i].x;
            sumy += p[i].y;
        }
        sort(p,p + n);
        int m = 1;
        for(int i = 1; i < n; i++)
        {
            if(p[i].x == p[i - 1].x && p[i].y == p[i - 1].y) continue;
            else p[m++] = p[i];
        }
        int ans = hull.convex(p,m,ch);
        double a,b,c;
        double res = 9999999999.0;
        //sort(ch, ch + ans);
        ch[ans] = ch[0];
        for(int i = 0; i < ans; i++)
        {
            a = ch[i + 1].y - ch[i].y;
            b = ch[i].x - ch[i + 1].x;
            c = ch[i].y * ch[i + 1].x - ch[i].x * ch[i + 1].y;
            double sum = (n - 2) * c + (sumx - ch[i].x - ch[i + 1].x) * a + (sumy - ch[i].y - ch[i + 1].y) * b;
            double sum1 = sum / sqrt(a * a * 1.0 + b * b * 1.0);
            if(dcmp(sum1) < res) res = dcmp(sum1);
        }
        if(n == 1) puts("0.000");
        else printf("%.3lf\n",res /(double)n);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值