Codeforces 605C Freelancer's Dreams 凸包 (看题解)

Freelancer's Dreams

我们把每个二元组看成是平面上的一个点, 那么两个点的线性组合是两点之间的连线, 即x * (a1, b1) + y * (a1, b1) && x + y == 1, 

那么n个点的线性组合就是一个凸包, 那么我们求出凸包和(0, 0)到(p, q)直线的交的那个较大值就是最优的组合平均速度。

需要注意的是, 直线和凸包可能没有交点, 需要加入(maxa, 0), (0, maxb)这两个点。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ull unsigned long long

using namespace std;

const int N = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

int dcmp(double x) {
    if(fabs(x) < eps) return 0;
    else return x < 0 ? -1 : 1;
}

struct Point {
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y) {}
};

double dist(const Point& a, const Point& b) {
    return sqrt((a.x-b.x) * (a.x-b.x) + (a.y-b.y) * (a.y-b.y));
}

typedef Point Vector;

Point operator + (Vector A, Vector B) {return Point(A.x + B.x, A.y + B.y);}
Point operator - (Vector A, Vector B) {return Point(A.x - B.x, A.y - B.y);}
Point operator * (Vector A, double p) {return Point(A.x * p, A.y * p);}
Point operator / (Vector A, double p) {return Point(A.x / p, A.y / p);}
bool operator < (const Vector &A, const Vector &B) {return A.x < B.x || (A.x == B.x && A.y < B.y);}
bool operator == (const Vector &A, const Point &B) {return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0;}
double Dot(Vector A, Vector B) {return A.x * B.x + A.y * B.y;}
double Length(Vector A) {return sqrt(Dot(A, A));}
double Angle(Vector A, Vector B) {return acos(Dot(A, B)/Length(A)/Length(B));}
double Cross(Vector A, Vector B) {return A.x * B.y - A.y * B.x;}
double Area2(Point A, Point B, Point C) {return Cross(B-A, C-A);}

bool IsPointOnSegment(const Point &p, const Point &a1, const Point &a2) {
    if(dcmp(Cross(a1-p,a2-p))) return 0;
    else if(dcmp(p.x-min(a1.x,a2.x)) >= 0 && dcmp(p.x-max(a1.x,a2.x)) <= 0
            && dcmp(p.y-min(a1.y,a2.y)) >= 0 && dcmp(p.y-max(a1.y,a2.y)) <= 0) return 1;
    else return 0;
}

Point GetLineIntersection(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 ConvexHull(vector<Point>& p, vector<Point>& ch) {
    int n = p.size(), m = 0;
    sort(p.begin(), p.end());
    for(int i = 0; i < n; i++) {
        while(m > 1 && dcmp(Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) <= 0) ch.pop_back(), m--;
        ch.push_back(p[i]); m++;
    }
    int k = m;
    for(int i = n - 2; i >= 0; i--) {
        while(m > k && dcmp(Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) <= 0) ch.pop_back(), m--;
        ch.push_back(p[i]); m++;
    }
    return m;
}

int n, p, q;
vector<Point> pt, ch;

int main() {
    scanf("%d%d%d", &n, &p, &q);
    int mxa = -inf, mxb = -inf;
    for(int i = 1; i <= n; i++) {
        int a, b; scanf("%d%d", &a, &b);
        mxa = max(mxa, a);
        mxb = max(mxb, b);
        pt.push_back(Point(a, b));
    }
    pt.push_back(Point(mxa, 0));
    pt.push_back(Point(0, mxb));
    int m = ConvexHull(pt, ch);
    Point v = Point(p, q);
    Point ans = Point(-1, -1);
    for(int i = 0; i < m - 1; i++) {
        if(dcmp(Cross(ch[i], v)) * dcmp(Cross(v, ch[i + 1])) >= 0) {
            if(Cross(v, ch[i + 1] - ch[i]) == 0) continue;
            Point pp = GetLineIntersection(Point(0, 0), v, ch[i], ch[i + 1] - ch[i]);
            if(pp.x > ans.x) ans = pp;
        }
    }
    printf("%.12f
", v.x / ans.x);
    return 0;
}

/*
*/
原文地址:https://www.cnblogs.com/CJLHY/p/10465578.html