HDU 4667 Building Fence(求凸包的周长)
Time Limit:1000MS Memory Limit:65535KB 64bit IO Format:%I64d & %I64u
Description
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
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
Sample Input
4 4 1
0 0 0 2 2 0
Sample Output
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(求凸包的周长)的更多相关文章
- HDU 4667 Building Fence 计算几何 凸包+圆
1.三角形的所有端点 2.过所有三角形的端点对所有圆做切线,得到所有切点. 3.做任意两圆的外公切线,得到所有切点. 对上述所有点求凸包,标记每个点是三角形上的点还是某个圆上的点. 求完凸包后,因为所 ...
- HDU 4667 Building Fence(2013多校7 1002题 计算几何,凸包,圆和三角形)
Building Fence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)To ...
- HDU 4667 Building Fence
题意: 给n个圆和m个三角形,且保证互不相交,用一个篱笆把他们围起来,求最短的周长是多少. 做法:--水过... 把一个圆均匀的切割成500个点,然后求凸包. 注意:求完凸包,在求周长的时候记得要把圆 ...
- hdu 4667 Building Fence < 计算几何模板>
//大白p263 #include <cmath> #include <cstdio> #include <cstring> #include <string ...
- (hdu step 7.1.7)Wall(求凸包的周长——求将全部点围起来的最小凸多边形的周长)
题目: Wall Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm ...
- 4667 Building Fence 解题报告
题意:给n个圆和m个三角形,且保证互不相交,用一个篱笆把他们围起来,求最短的周长是多少. 解法1:在每个圆上均匀的取2000个点,求凸包周长就可以水过. 解法2:求出所有圆之间的外公切线的切点,以及过 ...
- poj1873(二进制枚举+求凸包周长)
题目链接:https://vjudge.net/problem/POJ-1873 题意:n个点(2<=n<=15),给出n个点的坐标(x,y).价值v.做篱笆时的长度l,求选择哪些点来做篱 ...
- Wall--POJ1113(极角排序+求凸包)
http://poj.org/problem?id=1113 题目大意:现在要给n个点,让你修一个围墙把这些点围起来,距离最小是l 分析 :现在就是求凸包的周长然后再加上一个圆的周长 #includ ...
- (模板)poj1113(graham扫描法求凸包)
题目链接:https://vjudge.net/problem/POJ-1113 题意:简化下题意即求凸包的周长+2×PI×r. 思路:用graham求凸包,模板是kuangbin的. AC code ...
随机推荐
- python爬虫:利用BeautifulSoup爬取链家深圳二手房首页的详细信息
1.问题描述: 爬取链家深圳二手房的详细信息,并将爬取的数据存储到Excel表 2.思路分析: 发送请求--获取数据--解析数据--存储数据 1.目标网址:https://sz.lianjia.com ...
- 华为模拟器ensp代码错误2,41,40问题的解决
win8+ensp320 ensp这是个神奇的软件,问题竟然出现的这么莫名其妙..前一秒还是好的时候,后一秒就立马出现了问题.不过不要慌...沉住气,把这篇文章看下去. 博主从昨天开始,ensp神奇的 ...
- B-树 动机与结构
Ps.我们遵循从感性到理性的认知顺序来逐步探索B-树的奥秘,之前经常说的value这里用key(关键码)指代,因为可能存的是字符串,说是value就不合适了. (多图预警!!!建议在WI-FI下观看) ...
- 原理剖析-Netty之服务端启动工作原理分析(上)
一.大致介绍 1.Netty这个词,对于熟悉并发的童鞋一点都不陌生,它是一个异步事件驱动型的网络通信框架: 2.使用Netty不需要我们关注过多NIO的API操作,简简单单的使用即可,非常方便,开发门 ...
- 2599: [IOI2011]Race
2599: [IOI2011]Race 链接 分析 被memset卡... 点分治,对于重心,遍历子树,记录一个数组T[i],表示以重心为起点的长度为i的路径中最少的边数是多少.然后先遍历子树,更新答 ...
- SparkSteaming中直连与receiver两种方式的区别
SparkStreaming的Receiver方式和直连方式有什么区别? Receiver接收固定时间间隔的数据(放在内存中的),使用高级API,自动维护偏移量,达到固定的时间才去进行处理,效率低并且 ...
- 如何在一个顶级域名下用两个二级域名访问vps下的两个项目网站--完美解决骗
本人是原址是http://www.webzhe.com/server/340 后经过本人的实践修改,增加截图,等具体的步骤,完美解决 如何在vps中设置二级域名开通子网站,这个问题涉及到两步:一首先要 ...
- laravel5.5队列
目录 简单实例 1. 简介和配置 1.1 好处 1.2 配置文件 1.3 队列驱动的必要配置 2. 创建任务 2.1 生成任务类 2.2 修改任务类 2.3 分发任务 2.4 自定义队列 & ...
- USACO Section2.3 Zero Sum 解题报告 【icedream61】
zerosum解题报告----------------------------------------------------------------------------------------- ...
- mysql语法结构
环境:win7 64位.mysql 适合阅读者:对sql基本语法有一定了解 <建表语句>: create table <表名>( <列名> <类型> & ...