题目链接:传送门
题意:给你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;
}