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. MPP(大规模并行处理)

    1. 什么是MPP? MPP (Massively Parallel Processing),即大规模并行处理,在数据库非共享集群中,每个节点都有独立的磁盘存储系统和内存系统,业务数据根据数据库模型和 ...

  2. Codeforces Round #458C DP

    C. Travelling Salesman and Special Numbers time limit per test 1 second memory limit per test 256 me ...

  3. poj1182食物链

    Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到 ...

  4. [CodeForces954G]Castle Defense(二分答案+差分)

    Description 题目链接 Solution 二分答案,套一个差分标记即可 每次放弓箭手显然越右边越优 Code #include <cstdio> #include <alg ...

  5. python正则表达式02--findall()和search()方法区别,group()方法

    import re st = 'asxxixxsaefxxlovexxsdwdxxyouxxde' #search()和 findall()的区别 a = re.search('xx(.*?)xxsa ...

  6. Redis数据更新

    技术交流群: 233513714

  7. myeclipse中项目名有红叉,但项目中文件没有报错的解决办法

    导入了别人的项目,各种jar包都放好后,path也都build好了,项目也能正常启动,但是就是项目名有红叉,这是为什么呢? 网上有人说Java build path中的jar包missing了,这是一 ...

  8. oracle数据库DB_NAME、DBID、DB_UNIQUE_NAME等的区别

    目录 DB_NAME DBID DB_UNIQUE_NAME: INSTANCE_NAME: SID: SERVICE_NAME GLOBAL_DATABASE_NAME: DB_NAME ①是数据库 ...

  9. 《Cracking the Coding Interview》——第12章:测试——题目1

    2014-04-24 23:10 题目:找出下面代码里的错误. 解法:请看下面. 代码: // 12.1 What's wrong with the following code segment? # ...

  10. 能加载文件或程序集 HRESULT:0x80070057 (E_INVALIDARG)的异常的解决方案

    今天下午由于机器蓝屏后,导致我的VS不能够调试我的网站了. 症状就是 : VS无法调试,但是可以编译和发布.而且只是 我在调试时蓝屏的那个项目 不能调试. 出现的错误就是: 能加载文件或程序集“Eny ...