uva 11168

题意:有n个点,找一条直线,让所有点都在直线的同一侧(也可在直线上),且到直线的距离之和最小。输出距离和与点数的比值。

题解:所有点在直线同侧,也就是直线不能穿过凸包,那么凸包的边所在直线就是可能的解,点(x0,y0)到直线(Ax + By + C = 0)的距离

dis = |Ax0 + By0 + C| / sqrt(A^2 + B^2)

把凸包的每个边拿去计算,所有点到其的距离和,根据计算式,先把所有点的x坐标之和和y坐标之和计算出来减少时间复杂度。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const double PI = acos(-1);
const int N = 10005;
const double INF = 1e9;
struct Point {
    double x, y;
    Point(double x = 0, double y = 0): x(x), y(y) {}
}P[N], res[N];
struct Circle {
    Point c;
    double r;
    Circle() {}
    Circle(Point c, double r = 0): c(c), r(r) {}
    Point point(double a) {
        return Point(c.x + cos(a) * r, c.y + sin(a) * c.y);
    }
};
int n;
double Sqr(double x) {
    return x * x;
}
Point operator + (Point A, Point B) {
    return Point(A.x + B.x, A.y + B.y);
}
Point operator - (Point A, Point B) {
    return Point(A.x - B.x, A.y - B.y);
}
Point operator * (Point A, double p) {
    return Point(A.x * p, A.y * p);
}
Point operator / (Point A, double p) {
    return Point(A.x / p, A.y / p);
}
//计算点积的正负  负值夹角为钝角
int dcmp(double x) {
    if (fabs(x) < 1e-9)
        return 0;
    return x < 0 ? -1 : 1;
}
bool operator < (const Point& a, const Point& b) {
    return a.x < b.x || (a.x == b.x && a.y < b.y);
}
bool operator == (const Point& a, const Point& b) {
    return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
//计算点积
double Dot(Point A, Point B) {
    return A.x * B.x + A.y * B.y;
}
//计算叉积,也就是数量积
double Cross(Point A, Point B) {
    return A.x * B.y - A.y * B.x;
}
//计算向量长度
double Length(Point A) {
    return sqrt(Dot(A, A));
}
//向量A旋转rad弧度,rad负值为顺时针旋转
Point Rotate(Point A, double rad) {
    return Point(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));
}
//角度转化弧度
double torad(double deg) {
    return deg / 180.0 * PI;
}
int ConvexHull(Point* P, int& cnt, Point* res) {
    sort(P, P + cnt);
    cnt = unique(P, P + cnt) - P;
    int m = 0;
    for (int i = 0; i < cnt; i++) {
        while (m > 1 && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) <= 0)
            m--;
        res[m++] = P[i];
    }
    int k = m;
    for (int i = cnt - 2; i >= 0; i--) {
        while (m > k && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) <= 0)
            m--;
        res[m++] = P[i];
    }
    if (cnt > 1)
        m--;
    return m;
}

void change(double &A, double &B, double &C, Point a, Point b) {
    A = b.y - a.y;
    B = a.x - b.x;
    C = b.x * a.y - a.x * b.y;
}

int main() {
    int t, cas = 1;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        double sumx = 0, sumy = 0;
        for (int i = 0; i < n; i++) {
            scanf("%lf%lf", &P[i].x, &P[i].y);
            sumx += P[i].x;
            sumy += P[i].y;
        }
        if (n <= 2) {
            printf("Case #%d: 0.000\n", cas++);
            continue;
        }
        int temp = ConvexHull(P, n, res);
        double minn = INF;
        for (int i = 0; i < temp; i++) {
            double A, B, C;
            change(A, B, C, res[i], res[(i + 1) % temp]);
            double sumdis = fabs(A * sumx + B * sumy + C * n) / sqrt(Sqr(A) + Sqr(B));
            minn = min(minn, sumdis);
        }
        printf("Case #%d: %.3lf\n", cas++, minn / n);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-03 15:01:11

uva 11168的相关文章

UVa 11168 Airport , 凸包

题意: 给出平面上n个点,找一条直线,使得所有点在直线的同侧,且到直线的距离之平均值尽量小. 先求凸包 易知最优直线一定是凸包的某条边,然后利用点到直线距离公式进行计算. #include<cstdio> #include<cstring> #include<vector> #include<cmath> #include<algorithm> #include<iostream> using namespace std; struc

Airport UVA - 11168

Airport UVA - 11168 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 10010; 4 const int inf = 0x3f3f3f3f; 5 const int eps = 1e-12; 6 7 struct Point { 8 double x, y; 9 Point (double x = 0, double y = 0) : x(x), y(y) {} 10 }; 11 ty

UVa 11168 (凸包+点到直线距离) Airport

题意: 平面上有n个点,求一条直线使得所有点都在直线的同一侧.并求这些点到直线的距离之和的最小值. 分析: 只要直线不穿过凸包,就满足第一个条件.要使距离和最小,那直线一定在凸包的边上.所以求出凸包以后,枚举每个边求出所有点到直线的距离之和得到最小值. 点到直线距离公式为: 因为点都在直线同一侧,所以我们可以把加法“挪”到里面去,最后再求绝对值,所以可以预处理所有点的横坐标之和与纵坐标之和.当然常数C也要记得乘上n倍. 已知两点坐标求过该点直线的方程,这很好求不再赘述,考虑到直线没有斜率的情况,

UVA 11168(凸包算法)

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34780 Problem 给N个点,画一条直线,所有点都在直线一侧(可以在直线上),且到达直线的平均距离最小(实际上就是总距离最小).输出平均距离,N有10000级别,点坐标挺大. Solution 首先,求一个凸包,枚举凸包点边,O(1)求出所有点到边的距离,维护最小值即可. 首先,为啥枚举凸包的边是对的? 其次,怎么O(1)求出,设直线返程为Ax+By+C=0, 点(x0

简单几何(数学公式+凸包) UVA 11168 Airport

题目传送门 题意:找一条直线,使得其余的点都在直线的同一侧,而且使得到直线的平均距离最短. 分析:训练指南P274,先求凸包,如果每条边都算一边的话,是O (n ^ 2),然而根据公式知直线一般式为Ax + By + C = 0.点(x0, y0)到直线的距离为:fabs(Ax0+By0+C)/sqrt(A*A+B*B). 所以只要先求出x的和以及y的和,能在O (1)计算所有距离和. 两点式直线方程p1 (x1, y1),p2 (x2, y2)转换成一般式直线方程:A = y1 - y2, B

UVa 11168(凸包、直线一般式)

要点 找凸包上的线很显然 但每条线所有点都求一遍显然不可行,优化方法是:所有点都在一侧所以可以使用直线一般式的距离公式\(\frac{|A* \sum{x}+B* \sum{y}+C*n|}{\sqrt {A^2+B^2}}\)\(O(1)\)算出总距离 #include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #i

几何算法专题

UVA 10652 Board Wrapping UVA 11168 Airport UVA 1396 Most Distant Point from the Sea UVA 1298 Triathlon UVA 1475 Jungle Outpost UVA 10652 Board Wrapping #include<bits/stdc++.h> using namespace std; #define For(i,n) for(int i=1;i<=n;i++) #define Fo

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d

UVA 10341 Solve It

Problem F Solve It Input: standard input Output: standard output Time Limit: 1 second Memory Limit: 32 MB Solve the equation: p*e-x + q*sin(x) + r*cos(x) + s*tan(x) + t*x2 + u = 0 where 0 <= x <= 1. Input Input consists of multiple test cases and te