1. 程式人生 > >Gym 101673B Craters(凸包)

Gym 101673B Craters(凸包)

題目連結:傳送門

 

題意:給你n個圓的圓心座標和半徑,讓你求它們的外圍,且外圍與圓弧之間的距離要大於等於10.

 

思路:很明顯的一個凸包,所以我們將每個圓的圓弧上的點記錄下來(等分成5000份),然後進行凸包即可。

(好像精度有點差距,但奇妙的過了!)

 

附上程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 1000000000;
const int MAXN = 1000100;
struct point
{
	double x, y;
};
point list[MAXN];
int stack[MAXN], top;

double cross(point p0, point p1, point p2)
{
	return (p1.x - p0.x)*(p2.y - p0.y) - (p1.y - p0.y)*(p2.x - p0.x);
}
double dis(point p1, point p2) 
{
	return sqrt((double)(p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y));
}
bool cmp(point p1, point p2)  
{
	double tmp = cross(list[0], p1, p2);
	if (tmp>0) return true;
	else if (tmp == 0 && dis(list[0], p1)<dis(list[0], p2)) return true;
	else return false;
}
void init(int n)
{
	int i, k;
	point p0;
	p0.x = list[0].x;
	p0.y = list[0].y;
	k = 0;
	for (i = 1; i<n; i++)
	{
		if ((p0.y>list[i].y) || ((p0.y == list[i].y) && (p0.x>list[i].x)))
		{
			p0.x = list[i].x;
			p0.y = list[i].y;
			k = i;
		}
	}
	list[k] = list[0];
	list[0] = p0;

	sort(list+1, list + n, cmp);
}

void graham(int n)
{
	int i;
	if (n == 1) { top = 0; stack[0] = 0; }
	if (n == 2)
	{
		top = 1;
		stack[0] = 0;
		stack[1] = 1;
	}
	if (n>2)
	{
		for (i = 0; i <= 1; i++) stack[i] = i;
		top = 1;

		for (i = 2; i<n; i++)
		{
			while (top>0 && cross(list[stack[top - 1]], list[stack[top]], list[i]) <= 0) top--;
			top++;
			stack[top] = i;
		}
	}
}
int main(void) {
	int n;
	int summ = 0;
	scanf("%d", &n);
	double gg = PI/2500;
	for (int i = 0; i < n; i++) {
		double x, y,r;
		scanf("%lf%lf%lf", &x, &y,&r);
		r += 10;
		for (int j = 1; j <= 5000; j++) {
			list[summ].x = x + r*cos(gg*j);
			list[summ].y = y + r*sin(gg*j);
			summ++;
		}
	}
	init(summ);
	graham(summ);
	double ans = 0;
	for (int i = 0; i <= top; i++) {
		ans += dis(list[stack[i+1]], list[stack[i]]);
	}
	printf("%.10lf\n", ans);
	return 0;
}