题意略。
思路:求出凸包后,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 */