1. 程式人生 > >ZOJ——3871(Convex Hull)(計算幾何+凸包問題)

ZOJ——3871(Convex Hull)(計算幾何+凸包問題)

Edward has n points on the plane. He picks a subset of points (at least three points), and defines the beauty of the subset as twice the area of corresponding convex hull. Edward wants to know summation of the beauty of all possible subsets of points (at least three points).

No two points coincide and no three points are on the same line.

Input

There are multiple test cases. The first line of input contains an integer Tindicating the number of test cases. For each test case:

The first line contains an integer n (3 ≤ n ≤ 1000). Each of following n lines contains 2 integers xi, yi which denotes a point (xi, yi) (0 ≤ |xi|, |yi| ≤ 109).

 

The sum of values n for all the test cases does not exceed 5000.

Output

For each case, if the answer is S, output a single integer denotes S modulo 998244353.

Sample Input

1
3
0 0
0 1
1 0

Sample Output

1

題意:給n個點,求在所有情況下的子集下(子集點數>=3),凸包的面積和的兩倍。

題解:這題主要有幾個方面,一個是凸包的面積,還有就是,在180度以內的點數。見程式碼。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAX = 1010;
const int mod = 998244353;
const double PI = acos(-1.0);
struct hh{
	int x,y;//這裡用ll不對,我很迷
	double k;
}p[MAX],tp[MAX<<1];
int poww[MAX];
void init(){
	poww[0]=1;
	for(int i=1;i< MAX;++i){
		poww[i]=poww[i-1]*2%mod;//看有幾個凸包
	}
}
bool cmp(hh a,hh b){
	return a.k<b.k;//角度從小到大
}
int area(hh a,hh b){
	return(((ll)a.x*b.y%mod-(ll)a.y*b.x%mod)%mod+mod)%mod;//叉乘求面積,因為是2倍和,所以不用除以二
}
int main(){
	init();
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		for (int i = 0; i < n;i++){
			scanf("%d%d",&p[i].x,&p[i].y);
		}
		int ans=0;
		for (int i = 0; i < n;i++){
			int cnt=0;
			for (int j = 0; j < n;j++){
				if(i==j) continue;
				tp[cnt]=p[j];
				tp[cnt++].k=atan2(p[j].y-p[i].y,p[j].x-p[i].x);
			}
			for(int j = 0;j < n;j++){
				tp[j+cnt]=tp[j];
				tp[j+cnt].k+=2.0*PI;//防止角度是負數
			}
			sort(tp,tp+cnt*2,cmp);//極角排序
			int r=0;
			for (int l = 0;l < cnt;l++){//排完用一半,很迷
				while(tp[r+1].k-tp[l].k<PI)r++;
				ans=(ans+(ll)area(p[i],tp[l])*((poww[r-l]-1+mod)%mod)%mod)%mod;//直接乘凸包數目不是很懂
			}
		}
		printf("%d\n",ans);//同結構體,直接用ll報錯
	}
	return 0;
}

講真,不是很好理解,多多學習呀!