HDU 2907

题意略。

思路:求出凸包后,ans = 在凸包上的边 * q - 凹陷个数 * p。

              

一条边上,一个端点在凸包上,另一个端点在凸包内,则一定是凹陷的一条边,我们单向地来扫这些边,记录第一个点在凸包上,而第二个点不在凸包上的边的

个数,这些记录的总和也就是凹陷的总数。由于一个凹陷总是可以被凸包上的一条边覆盖住,所以我们最终的答案也可以表示为:

凸包上的边数 * q - 凹陷数 * q(不该加上) - 凹陷数 * p

详见代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 50;
const double eps = 1e-6;

struct Point{
    double x,y;
    int id;
    Point(double a = 0,double b = 0){
        x = a,y = b;
    }
    Point operator -(const Point& b) const{
        return Point(x - b.x,y - b.y);
    }
    double operator ^(const Point& b) const{
        return x * b.y - y * b.x;
    }
    double operator *(const Point& b) const{
        return x * b.x + y * b.y;
    }
};
struct line{
    Point bg,ed;
    line(){}
    line(Point a,Point b){
        bg = a,ed = b;
    }
};

Point List[maxn];
int Stack[maxn],top,ison[maxn];

int sgn(double f){
    if(fabs(f) < eps) return 0;
    else if(f < 0) return -1;
    else return 1;
}
double dist(Point p1,Point p2){
    double dx = p1.x - p2.x;
    double dy = p1.y - p2.y;
    return sqrt(dx * dx + dy * dy);
}
bool cmp(const Point& p1,const Point& p2){
    double tmp = (p1 - List[0]) ^ (p2 - List[0]);
    if(sgn(tmp) > 0) return true;
    else if(sgn(tmp) == 0 && sgn(dist(p1,List[0]) - dist(p2,List[0])) <= 0) return true;
    return false;
}
void Graham(int n){
    Point p0;
    int k = 0;
    p0 = List[0];
    for(int i = 1;i < n;++i){
        if((p0.y > List[i].y) || (p0.y == List[i].y && p0.x > List[i].x)){
            p0 = List[i];
            k = i;
        }
    }
    swap(List[k],List[0]);
    sort(List + 1,List + n,cmp);
    if(n == 1){
        top = 1;
        Stack[0] = 0;
        return;
    }
    if(n == 2){
        top = 2;
        Stack[0] = 0;
        Stack[1] = 1;
        return;
    }
    Stack[0] = 0;
    Stack[1] = 1;
    top = 2;
    for(int i = 2;i < n;++i){
        while(top > 1 && sgn((List[Stack[top - 1]] - List[Stack[top - 2]]) ^ (List[i] - List[Stack[top - 2]])) <= 0)
            --top;
        Stack[top++] = i;
    }
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int p,q,n;
        top = 0;
        memset(ison,0,sizeof(ison));
        scanf("%d%d%d",&p,&q,&n);
        for(int i = 0;i < n;++i){
            scanf("%lf%lf",&List[i].x,&List[i].y);
            List[i].id = i;
        }
        int ans = 0;
        int cnt = 0;
        Graham(n);
        for(int i = 0;i < top;++i){
            ison[List[Stack[i]].id] = 1;
        }
        ison[n] = ison[0];
        for(int i = 0;i < n;++i){
            if(ison[i] == 1 && ison[i + 1] == 0)
            {
                ++cnt;
            }
        }
        ans = top * q - cnt * p - cnt * q;
        printf("%d
",max(ans,0));
    }
    return 0;
}

/*
1 
10 5 7
0 10
8 4
10 -7
6 -9
-5 -4
-5 7
-2 6

15
*/

/*
1
10 5 8
0 8
0 10
8 4
10 -7
6 -9
-5 -4
-5 7
-2 6

15
*/
原文地址:https://www.cnblogs.com/tiberius/p/9292861.html