题目链接:传送门
题意:
给定n个圆,m个三角形求把这些图形全部覆盖的图形的最小的周长。
分析:
刚开始看到就想到了求凸包,可是圆怎么求了?就暴力把圆分割成1000个点然后求凸包就可以了。水过了,正解是找圆与圆的切点圆与三角形上的点与圆引得切线的切点。
代码如下:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long LL;
const double eps = 1e-10;
const int maxn = 1e6+10;
const double pi = acos(-1.0);
const double inf = 1e17;
int dcmp(double x){
if(fabs(x)<eps) return 0;
if(x>0) return 1;
return -1;
}
struct point{
double x,y;
int id;
point(){}
point(double _x,double _y,int i):x(_x),y(_y),id(i){}
bool operator <(const struct point &tmp)const{
if(dcmp(x-tmp.x)==0) return dcmp(y-tmp.y)<0;
return dcmp(x-tmp.x)<0;
}
bool operator == (const struct point &tmp)const{
return dcmp(x-tmp.x)==0&&dcmp(y-tmp.y)==0;
}
}p[maxn],st[maxn];
double Cross(point a,point b,point c){
return (c.x-a.x)*(b.y-a.y) - (b.x-a.x)*(c.y-a.y);
}
int ConvexHull(point *p,int n,point *st){
sort(p,p+n);
n=unique(p,p+n)-p;
int m=0;
for(int i=0; i<n; i++) {
while(m>1&&Cross(st[m-2],p[i],st[m-1])<=0) m--;
st[m++]=p[i];
}
int k=m;
for(int i=n-2; i>=0; i--){
while(m>k&&Cross(st[m-2],p[i],st[m-1])<=0)m--;
st[m++]=p[i];
}
if(n>1) m--;
return m;
}
double dis(point a,point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int R[600];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
int cnt = 0;
for(int i=0;i<n;i++){
double x,y,r;
scanf("%lf%lf%lf",&x,&y,&r);
R[i]=r;
for(int j=0;j<1000;j++){
double tmp = 2*pi*j/1000;
p[cnt++]=point(x+r*cos(tmp),y+r*sin(tmp),i);
}
}
for(int i=0;i<m*3;i++){
double x,y;
scanf("%lf%lf",&p[cnt].x,&p[cnt].y);
p[cnt].id=cnt++;
}
int num = ConvexHull(p,cnt,st);
double ans = 0;
for(int i=0;i<num;i++){
int t1 = st[i].id;
int t2 = st[(i+1)%num].id;
if(t1==t2){
ans+=pi*2*R[t1]/1000;
}
else ans+=dis(st[i],st[(i+1)%num]);
}
printf("%.4lf\n",ans);
}
return 0;
}