A - Building Fence

Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u

Submit Status

Description

Long long ago, there is a famous farmer named John. He owns a big farm and many cows. There are two kinds of cows on his farm, one is Friesian, and another one is Ayrshire. Each cow has its own territory. In detail, the territory of Friesian is a circle, and of Ayrshire is a triangle. It is obvious that each cow doesn't want their territory violated by others, so the territories won't intersect.

Since the winter is falling, FJ has to build a fence to protect all his cows from hungry wolves, making the territory of cows in the fence. Due to the financial crisis, FJ is currently lack of money, he wants the total length of the fence minimized. So he comes to you, the greatest programmer ever for help. Please note that the part of fence don't have to be a straight line, it can be a curve if necessary.

 

Input

The input contains several test cases, terminated by EOF. The number of test cases does not exceed 20. 
Each test case begins with two integers N and M(0 ≤ N, M ≤ 50, N + M > 0)which denotes the number of the Friesian and Ayrshire respectively. Then follows N + M lines, each line representing the territory of the cow. Each of the first N lines contains three integers Xi, Y i, R i(1 ≤ R i ≤ 500),denotes the coordinates of the circle's centre and radius. Then each of the remaining M lines contains six integers X1 i, Y1 i, X2 i, Y2 i, X3 i, Y3 i, denotes the coordinates of the triangle vertices. The absolute value of the coordinates won't exceed 10000.
 

Output

For each test case, print a single line containing the minimal fence length. Your output should have an absolute error of at most 1e-3.
 

Sample Input

1 1
4 4 1
0 0 0 2 2 0
 

Sample Output

15.66692

Hint

 Please see the sample picture for more details, the fence is highlighted with red.

题意:给定n个圆,m个三角形,求凸包的周长,详见上图。
题解:这个题有一种很水的做法就是把圆分成1000个点,然后直接对这些点求凸包。
   不推荐这个方法,属于水过的,换个精度高的数据没准就WA了,正确做法如下:
   把三角形的所有点视为单个点,标记三角形每个点的id为-1,-2,-3,-4.......放到一个集合P中,
   求这些点与圆的切线的交点,把这些点再放到集合P中,标记他们的id为圆的数组下标。
   再求圆与圆之间的内切线外切线与圆的交点,再放到集合P中,标记他们的id为圆的数组下标,
   把这些点进行凸包就可以求出周长了,id相同的点要算弧长。很多很多细节问题需要注意,已写到注释里。
   另外注意在没有三角形只有一个圆的情况下要单独考虑,因为不会通过点和圆之间
   的切线以及圆和圆之间的切线产生点,所以要单独判断然后输出圆的面积,
   continue即可。
   对于数组为什么开2W,目前未知,求大神解答。
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <vector>
const double PI=acos(-1.0);
using namespace std;
struct Point{
double x,y;
int id;
Point(double x=,double y=,int id=-):x(x),y(y){} //构造函数,方便代码编写
};
typedef Point Vector; //从程序上实现,Vector只是Point的别名
struct Circle{
Point c;
double r;
Circle() {}
Circle(Point c,double r):c(c),r(r){}
Point point(double a){
return Point(c.x+cos(a)*r,c.y+sin(a)*r);
}
};
//定义
#define N 50000 //数组最小开20000 为什么开20000没算对
//我算的是 150+300+C(50,2)*4 即三角形的点+这些点与圆的切点+圆之间的切点 不到6000
//开大点就完了 开500000 才 42344KB 上限65536 够用了
Point p[N];
Point ch[N];
Circle c[N];
Point a[],b[];
Point q[N];
int m,n,t;
//点-点=向量
Vector operator - (Point A,Point B)
{
return Vector(A.x-B.x,A.y-B.y);
}
//运算符重载
bool operator <(const Point &a,const Point &b)
{
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double eps=1e-;
//三态函数精度问题
int dcmp(double x)
{
if(fabs(x)<eps) return ; else return x<?-:;
}
bool operator ==(const Point &a,const Point &b)
{
return dcmp(a.x-b.x)==&&dcmp(a.y-b.y)==;
}
double Dot(Vector A,Vector B)
{
return A.x*B.x+A.y*B.y;
}
//求向量的值
double Length(Vector A)
{
return sqrt(Dot(A,A));
}
//求夹角
double Angle(Vector A,Vector B)
{
return acos(Dot(A,B)/Length(A)/Length(B)); //a*b=|a|*|b|*cos(c)
}
//叉积
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
//求凸包模板
int ConvexHull(Point *p,int n,Point* ch) //注意是*ch
{
sort(p,p+n); //这个要用到<重载运算符
n=unique(p,p+n)-p; //这个要用到==重载运算符
int m=;
for(int i=;i<n;i++)
{
//注意:可以共线时"<"改为"<="
while(m>&&Cross(ch[m-]-ch[m-],p[i]-ch[m-])<=) m--;
ch[m++]=p[i];
}
int k=m;
for(int i=n-;i>=;i--) //注意是--不是++
{
while(m>k&&Cross(ch[m-]-ch[m-],p[i]-ch[m-])<=) m--;
ch[m++]=p[i];
}
if(n>) m--;
return m;//别忘了加m
}
Point readpoint()
{
double x,y;
scanf("%lf%lf",&x,&y);
return Point(x,y);
}
void readcircle(Circle &c)
{
scanf("%lf%lf%lf",&c.c.x,&c.c.y,&c.r);
}
//点到圆的切线 v存的是切点
int pcl(Point p,Circle o,Vector* v)//点到圆的切线的切点,考虑不同情况
{
Vector u=p-o.c;
double d=Length(u);
double a=atan2(u.y,u.x);//指向量u与x正半轴的夹角 起点是圆心 指向p点
if(d<o.r)return ;//圆内
else if(dcmp(d-o.r)==)//圆上
{
v[]=o.point(a);
return ;
}
else //圆外 两个外切点
{
double ang=acos(o.r/d);
v[]=o.point(a+ang);
v[]=o.point(a-ang);
return ;
}
}
//两圆相离的时候的外公共切线
int ccl(Circle c1,Circle c2,Point *a,Point *b)
{
int cnt=;
if(dcmp(c1.r-c2.r)<)//保证结果为正值
{
swap(c1,c2);
swap(a,b);
} Vector u=c2.c-c1.c;
double d=Length(u);
double ang=atan2(u.y,u.x);
//有外公切线
double g=acos((c1.r-c2.r)/d);
a[cnt]=c1.point(ang+g);
b[cnt]=c2.point(ang+g);
cnt++;
a[cnt]=c1.point(ang-g);
b[cnt]=c2.point(ang-g);
cnt++;
return cnt;
}
double arc(Point a,Point b,Circle c)//a,b逆时针穿过圆c外面的的圆弧长
{
Point u=a-c.c,v=b-c.c;
double ang=Angle(u,v); //Angle 是夹角 模板中的angle=atan2(v.y,v.x)是极角
if(Cross(u,v)>eps)
return ang*c.r;
return (PI*2.0-ang)*c.r;
}
int main()
{
while(scanf("%d%d",&n,&m)==)
{
m=m*;
for(int i=; i<n; i++) //圆
readcircle(c[i]);
for(int i=; i<m; i++) //三角形
{
p[i]=readpoint();
p[i].id=-i*-; //三角形的id标记成负数
}
if(n==&&!m)
{
printf("%.5f\n",PI**c[].r);; //输出一个圆的面积
continue;
}
// 注意 swap是把数值换位置 n和m不换位置
for(int i=m-; i>=; i--) //三角形的点 已经乘过3了
for(int j=; j<n; j++) //圆
{
Point v[]; //存放切点
int num=pcl(p[i],c[j],v); //点到圆的切线 p是点 c是圆 v是切点 num是切点个数
for(int k=; k<num; k++)
{
//从三角形的点中继续添加点
p[m]=v[k];//把切点放入点集中
p[m].id=j;//给新的点做标记 这个点是第j个圆的
m++;
}
}
for(int j=; j<n; j++)
for(int i=j+; i<n; i++)
{
int num=ccl(c[j],c[i],a,b); //圆和圆之间的外切点
for(int k=; k<num; k++)
{
p[m]=a[k];
p[m].id=j;
m++;
p[m]=b[k];
p[m].id=i;
m++;
}
}
m=ConvexHull(p,m,ch);
memcpy(p,ch,sizeof(ch));
double len=0.0;
p[m]=p[];
for(int i=; i<m; i++)
{
if(p[i].id==p[i+].id) //如果标记相等说明在一个圆上
{
len+=arc(p[i],p[i+],c[p[i].id]); //两个点绕圆弧逆时针的长
}
else
{
len+=Length(p[i]-p[i+]);//不在一个圆上输出算直线距离
}
}
printf("%.5f\n",len);
}
return ;
}

 

HDU 4667 Building Fence(求凸包的周长)的更多相关文章

  1. HDU 4667 Building Fence 计算几何 凸包+圆

    1.三角形的所有端点 2.过所有三角形的端点对所有圆做切线,得到所有切点. 3.做任意两圆的外公切线,得到所有切点. 对上述所有点求凸包,标记每个点是三角形上的点还是某个圆上的点. 求完凸包后,因为所 ...

  2. HDU 4667 Building Fence(2013多校7 1002题 计算几何,凸包,圆和三角形)

    Building Fence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)To ...

  3. HDU 4667 Building Fence

    题意: 给n个圆和m个三角形,且保证互不相交,用一个篱笆把他们围起来,求最短的周长是多少. 做法:--水过... 把一个圆均匀的切割成500个点,然后求凸包. 注意:求完凸包,在求周长的时候记得要把圆 ...

  4. hdu 4667 Building Fence < 计算几何模板>

    //大白p263 #include <cmath> #include <cstdio> #include <cstring> #include <string ...

  5. (hdu step 7.1.7)Wall(求凸包的周长——求将全部点围起来的最小凸多边形的周长)

    题目: Wall Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  6. 4667 Building Fence 解题报告

    题意:给n个圆和m个三角形,且保证互不相交,用一个篱笆把他们围起来,求最短的周长是多少. 解法1:在每个圆上均匀的取2000个点,求凸包周长就可以水过. 解法2:求出所有圆之间的外公切线的切点,以及过 ...

  7. poj1873(二进制枚举+求凸包周长)

    题目链接:https://vjudge.net/problem/POJ-1873 题意:n个点(2<=n<=15),给出n个点的坐标(x,y).价值v.做篱笆时的长度l,求选择哪些点来做篱 ...

  8. Wall--POJ1113(极角排序+求凸包)

    http://poj.org/problem?id=1113 题目大意:现在要给n个点,让你修一个围墙把这些点围起来,距离最小是l 分析  :现在就是求凸包的周长然后再加上一个圆的周长 #includ ...

  9. (模板)poj1113(graham扫描法求凸包)

    题目链接:https://vjudge.net/problem/POJ-1113 题意:简化下题意即求凸包的周长+2×PI×r. 思路:用graham求凸包,模板是kuangbin的. AC code ...

随机推荐

  1. Mysql:case when then end 的用法

    0.创建一张数据表 表名为 test_when_case CREATE TABLE `test_when_case` ( `id` int(11) unsigned NOT NULL AUTO_INC ...

  2. POJ 1222 反转

    EXTENDED LIGHTS OUT Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 12469   Accepted: 7 ...

  3. div嵌套img高度不相同

    div中嵌套img,如果div里嵌套一个img元素且div的高度是由img的高度来撑开,那么div的高度总会比img的高度多3px. 可以明显看到div实际高度高出img高度3px.为了解决此问题,我 ...

  4. django中间件CsrfViewMiddleware源码分析,探究csrf实现

    Django Documentation csrf保护基于以下: 1. 一个CSRF cookie 基于一个随机生成的值,其他网站无法得到.此cookie由CsrfViewMiddleware产生.它 ...

  5. 使用 jQuery Mobile 与 HTML5 开发 Web App 系列文章目录

    使用 jQuery Mobile 与 HTML5 开发 Web App 系列文章目录 时间:2012年9月20日 分类:JavaScript 标签:HTML5‚ jQuery Mobile‚ Web ...

  6. jpg、png、gif图片格式的浅析

    原文地址:图片格式与设计那点事儿 之前面试时被面试官问到了jpg.gif.png格式的区别,当时就扯了一些,感觉都是扯淡,上网搜了下,分享一篇文章 第一次写技术博客,有不尽如人意的地方,还请见谅和指正 ...

  7. 在SqlServer中通过SQL语句实现树状查询

    CREATE PROCEDURE [dbo].[GetTree] @Id int AS BEGIN with cte as ( as lvl from Entity where Id = @Id un ...

  8. Spring整合EhCache详解

    一.EhCache介绍 EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider.Ehcache是一种广泛使用的开 源Java分布 ...

  9. Python 实现MD5加密

    from hashlib import md5 def encrypt_md5(s): # 创建md5对象 new_md5 = md5() # 这里必须用encode()函数对字符串进行编码,不然会报 ...

  10. HDU 4472 Count (DP)

    题目:问n个节点构成完全对称的树有多少种方法. 因为树是完全对称的,所以它的子树也是完全对称的. 对于每个树,拿出一个根节点,枚举剩下的节点能拆分成多少个子树. #include <cstdio ...