swust oj 249 求凸包面積板子

短尾黑貓發表於2020-11-13

分治求出凸點,累加每個三角形的面積得到最終答案。三角形面積等於叉積的一半。

程式碼如下:

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#define sc scanf
#define pf printf
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const int N = 2e3 + 10;

PII node[N];
double ans = 0;

//判斷方向,1為正方向(逆時針),0為負方向。 
int dir(PII a, PII b, PII c)
{
	int x1 = b.first - a.first;
	int y1 = b.second - a.second;
	int x2 = c.first - a.first;
	int y2 = c.second - a.second;
	if(x1 * y2 - y1 * x2 > 0) return 1;
	return 0;
}

//叉積求面機。 
double getArea(PII a, PII b, PII c)
{
	return fabs(0.5 * (a.first * b.second + b.first * c.second + c.first * a.second - a.first * c.second - b.first * a.second - c.first * b.second));
}

//累加三角形面積,其中 l 和 r 是左右兩個頂點。 
void calc(int type, int l, int r)
{
	int k = -1;
	double temp_area = 0;
	//在區間[l+1, r-1]之間找到第三個頂點。 
	for(int i = l + 1; i < r; i++) {
		//方向不同則略過。 
		if(dir(node[l], node[i], node[r]) != type) continue;
		double this_area = getArea(node[l], node[i], node[r]);
		//更新當前最大面機。 
		if(temp_area - this_area < eps) {
			temp_area = this_area;
			k = i;
		}
	}
	if(k == -1) return ;
	ans += temp_area;
	calc(type, l, k);
	calc(type, k, r);
}

void solve()
{
	ans = 0.0;
	int n;
	cin >> n;
	for(int i = 0; i < n; i++) cin >> node[i].first >> node[i].second;
	sort(node, node + n);
	calc(1, 0, n - 1), calc(0, 0, n - 1);
	cout << fixed << setprecision(1) << ans << endl;
}

int main()
{
	#ifdef Yuew
		freopen("in.txt", "r", stdin);
	#endif //Yuew
	int t; cin >> t; while(t--) solve(); 
	return 0;
 } 

相關文章