HDU 6129 Hard challenge(极角排序+扫描法)

题目链接:HDU 6129

题意:

  给出n个点的坐标(x, y),每个点的值v,每两个点之间相连成一条线段,线段的值为两个端点值的乘积,保证没有重点、没有一条线段所在直线过原点。作一条过原点(不过给出的n个点)的直线与这些线段相交,求这些与直线相交的线段的值总和的最大值。

分析:

  过原点作一条直线会将n个点分成左右两部分,与这条直线相交的线段的值的总和转化为左半部分点的和乘于右半部分点的和。将所有点极角排序,扫描一遍。

代码实现:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 50000 + 5;
struct Point{
    LL x, y, v;
    double rad;
    bool operator <(const Point &rhs) const {
        return rad < rhs.rad;
    }
}p[N];
LL sum, lsum, ans;

bool left(Point A, Point B)//点B是否在点A的左侧
{
    return (A.x * B.y - A.y * B.x >= 0);
}
int main()
{
    int T, n;
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        sum = 0LL;//所有点的总值
        for (int i = 0; i < n; i++) {
            scanf("%lld%lld%lld", &p[i].x, &p[i].y, &p[i].v);
            p[i].rad = atan2(p[i].y, p[i].x);
            sum += p[i].v;
        }
        sort(p, p + n);
        int L = 0, R = 0;
        lsum = 0LL;//左半部分点的总值
        ans = 0LL;
        while (L < n) {
            if (R == L) R = (R + 1) % n;
            while (R != L && left(p[L], p[R])) {
                lsum += p[R].v;
                R = (R + 1) % n;
            }
            ans = max(ans, (LL)lsum * (sum - lsum));
            L++;
            lsum -= p[L].v;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

  

posted @ 2017-08-16 21:43  From-scratch  阅读(191)  评论(0)    收藏  举报