ZOJ 3871 Convex Hull(计算几何、凸包)

题意:给n个点,|x[i]|,|y[i]| <= 1e9。求在所有情况下的子集下(子集点数>=3),凸包的面积和。

这题主要有几个方面,一个是凸包的面积,可以直接用线段的有向面积和求得,这个当时没想到。还有就是,在180度以内的点数。

所以实际上是枚举2个点作为某个凸包的一条边,看有多少个这样的凸包。那个2^num - 1是保证除了2个点外至少还需1个点才能构成凸包。

时间复杂度O(n*n*logn)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;

const double pi = acos(-1.0);
#define ll long long
#define maxn 1010
#define mod 998244353
int area2(int ax, int ay, int bx, int by){
	return ((1ll*ax*by%mod-1ll*ay*bx%mod)%mod+mod)%mod;
}
struct Pnt{
	int x,y;
	double ang;
	bool operator < (const Pnt &b) const{
		return ang < b.ang;
	}
}vec[maxn<<1];
int p2[maxn];
int main(){
	p2[0]=1;
	for(int i=1;i<=1000;++i) p2[i] = (p2[i-1]<<1)%mod;
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		int x[maxn],y[maxn];
		for(int i=0;i<n;++i){
			scanf("%d%d",x+i,y+i);
		}
		int ans = 0;
		for(int i=0;i<n;++i){
			for(int j=0;j<n;++j){
				vec[j].x = x[j];
				vec[j].y = y[j];
				vec[j].ang = atan2(x[j]-x[i],y[j]-y[i]);
			}
			vec[i] = vec[n-1];
			for(int j=0;j<n-1;++j){
				vec[j+n-1] = vec[j];
				vec[j+n-1].ang += pi*2;
			}
			int nn = n-1+n-1;
			sort(vec,vec+nn);
			int l=0,r=0;
			while(l<n-1){
				while(r<nn && vec[r].ang - vec[l].ang < pi) r++;
				int area = area2(x[i],y[i],vec[l].x,vec[l].y);
				int cnt = (p2[r-l-1]-1+mod)%mod;
				ans = (ans+1ll*area*cnt%mod)%mod;
				++l;
			}
		}
		printf("%d
",(mod-ans)%mod);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/nextbin/p/4466912.html