题目:

给你三个城市A,B,C,要以某点为中心F,分别向三个城市建立三条道路。长度分别为FA,FB,FC.总花费为aFA+bFB+cFC

求(aFA+bFB+cFC)min

解决:

a=b=c时,那么F点即为费马点。

当不等时为费马点的拓展。

此时可以求出AFB,BFC,CFA三个角,具体如下图所示

特殊地a=b=c 三个角均为120.

百科上的介绍为如下:

对于每一个角小于120°的三角形ABC的每一条边为底边,向外做正三角形,然后做这个正三角形的外接圆。费马点即使这些圆的交点。

物理学的解释:

费马问题可以用物理的方法来解决。将平面上所给的三个给定点钻出洞来,再设桑格绳子系在同一个点上面,而绳子的末端都绑一个重量为m的重物。假设摩擦力可以忽略不计,那么绳子会被拉紧,而绳子的最后会停在平面一点上方。可以证明,这个点就是三个顶点所对应的费马点。首先由于绳子长度是固定的,而绳子竖直下垂的部分越长,重物的位置也就越低。势能也就越低。在平衡状态时,势能达到最小值,也就是绳子垂直下垂的部分长度达到最大值,而绳子水平长度为FA+FB+FC,因此FA+FB+FC最小,也就是达到费马点。有力学平衡定理,可以得到各个夹角为120°

从上面推广费马点定义,我们可以得出该题求的就是费马点。

至于公式直接解出费马,表示不知道。

我设计了如下算法:

首先我们可以求角ABF 以及 角ABC,以及角CBF.该标记对应上图。

代码对应如下:

angAB = acos(( n*n-l*l-m*m ) / (2*l*m));

angAC = acos(( m*m-l*l-n*n ) / (2*l*n));

angBC = acos(( l*l-m*m-n*n ) / (2*n*m));

这些角度与l,m,n也就是上面提到的aFA+bFB+cFC三个中的a,b,c.

注意到上面画红线部分。O1,O2,O3三个圆交与同一个点 B=D=E.

该点其实就是所求费马点。

首先费马点不一定存在

当(l,m,n)三条边不能组成三角形的时候需要特判。因为此时上面的公式不能求出角度了。

另者,当有两个点重合时,也就是其实不是三角形而是一条直线时,也需要特判,用定比分点解出答案。并且,求出的费马点可能在三角形外,此时,我们只要同时算出三个顶点的花费,取最小值即可

现在我们的问题就是严格的三角形内求可存在的费马点。

O1,O2,O3是这样求出来的。

比如O1.角ABC用公式得出 r = AC / sin(角ABC)/2 O1是以两个以A,C为圆心,r为半径的两个圆的交点。注意到此时有两个交点,当角ABC为钝角时 O1与(AC的对应点F)异侧,否则为同侧。当ABC为锐角时O1与(AC的对应点F)同侧,否则为异侧。这样我们只要求A,C两圆的交点,在经过这样的判断可解除唯一的O1.同理可以求出O2,O3.

再O1,O2求交点,求出两个交点,然后再判断与O3的距离。这样就可以得到唯一的点B。

该点即为费马点。可以知道该点满足那求出来的三个角的关系。此题精度要求较高。需要在调整下精度。

/*Author : LitData : July 17 1:00
*/#include<iostream>
#include<cstdio>
#include<cmath>using namespace std;const long double eps = 1e-10;
const double pi = acos(-1.0);
struct point
{long double x,y;
} fi,se,p0,p1,p2,third,ans;
struct Circle
{long double x,y;long double r;
} O,A,B,first,second;
int Test;
struct seg
{long double a,b,c;
} line;
bool bo;
long double angAB,angBC,angAC,l,m,n,r,fans,a,b;long double dis( point A, point B){return sqrt( (B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y) );
}
long double cross(point A,point B,point C){return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);
}seg get_vertical( seg line , point ret)
{seg lineA;lineA.a = line.b; lineA.b = -line.a; lineA.c = -(lineA.a*ret.x+lineA.b*ret.y);return lineA;
}
point get_cross( seg line , seg lineA)
{point ret;ret.x = -(line.c*lineA.b - lineA.c*line.b) / (line.a*lineA.b-line.b*lineA.a);ret.y = -(line.a*lineA.c - lineA.a*line.c) / (line.a*lineA.b-line.b*lineA.a);return ret;
}
void Segment_Circle(Circle O,seg line,point &fi,point &se)
{point ret,rett;ret.x = O.x; ret.y = O.y;seg lineA;lineA = get_vertical( line , ret );   if ( fabs(line.a)<eps )  {ret.x = 1; ret.y = 0;} elseif ( fabs(line.b)<eps ){ret.x = 0; ret.y = 1;} else{ret.x = 1; ret.y = -line.a/line.b;}long double dist = fabs( line.a*O.x + line.b*O.y +line.c ) / (sqrt( line.a*line.a + line.b*line.b ) );
//  cout << O.r*O.r - dist*dist << endl;dist = sqrt(O.r*O.r - dist*dist+eps);rett.x = ret.x / sqrt( ret.x*ret.x + ret.y*ret.y);rett.y = ret.y / sqrt( ret.x*ret.x + ret.y*ret.y);ret = rett;rett = get_cross(line,lineA);fi.x = rett.x+dist*ret.x; fi.y = rett.y+dist*ret.y;se.x = rett.x-dist*ret.x; se.y = rett.y-dist*ret.y;
}
void Circle_Circle(Circle A,Circle B,point &fi,point &se)
{seg lineA;lineA.a = 2*(B.x-A.x);lineA.b = 2*(B.y-A.y);lineA.c = -(A.r*A.r-A.x*A.x-A.y*A.y+B.x*B.x+B.y*B.y-B.r*B.r);Segment_Circle(A,lineA,fi,se);
}
void out(point A){printf("%.6lf %.6lf\n",(double)A.x,(double)A.y);
}void out(Circle A){printf("%.6lf %.6lf %.6lf\n",(double)A.x,(double)A.y,(double)A.r);
}
bool same( point A,point B){return (fabs(A.x-B.x)<eps) && (fabs(A.y-B.y)<eps);
}void work(){cin >> p0.x >> p0.y >> p1.x >> p1.y >> p2.x >> p2.y;cin >> l >> m >> n;bo = 1;if ( same(p0,p1) || same(p1,p2) || same(p0,p2) ){bo = 0; return;}if (l>=m+n) {ans = p0; return;} else if (m>=l+n) {ans = p1; return;} elseif (n>=l+m) {ans = p2; return;}angAB = acos(( n*n-l*l-m*m ) / (2*l*m));angAC = acos(( m*m-l*l-n*n ) / (2*l*n));angBC = acos(( l*l-m*m-n*n ) / (2*n*m));
/*cout << angAB/3.1415926*180 << endl;cout << angBC/3.1415926*180 << endl;cout << angAC/3.1415926*180 << endl;
*//*first circle*/r = dis( p0,p1) / sin( angAB ) / 2;A.x = p0.x; A.y = p0.y; A.r = r;B.x = p1.x; B.y = p1.y; B.r = r;
/*fi.x = A.x; fi.y = A.y;se.x = B.x; se.y = B.y;cout << dis(fi,se) << endl;
*/Circle_Circle(A,B,fi,se);if ( ( cross(p0,p1,fi)*cross(p0,p1,p2)<0 ) == (angAB>pi/2) ) {first.x = fi.x; first.y = fi.y; first.r = r;}  else{first.x = se.x; first.y = se.y; first.r = r;}/*second circle*/
//  out(A); out(B);
//  out(first);
//  cout << angBC/3.1415926*180 << endl;r = dis(p1,p2) / sin( angBC ) / 2;A.x = p1.x; A.y = p1.y; A.r = r;B.x = p2.x; B.y = p2.y; B.r = r;Circle_Circle(A,B,fi,se);if ( ( cross(p1,p2,fi)*cross(p1,p2,p0)<0 ) == (angBC>pi/2) ) {second.x = fi.x; second.y = fi.y; second.r = r;} else{second.x = se.x; second.y = se.y; second.r = r;}
//  out(second);/*third circle 's O*/r = dis(p2,p0) / sin( angAC ) /2;A.x = p2.x; A.y = p2.y; A.r = r;B.x = p0.x; B.y = p0.y; B.r = r;Circle_Circle(A,B,fi,se);if ( ( cross(p2,p0,fi)*cross(p2,p0,p1)<0 ) == (angAC>pi/2) ) {third.x = fi.x; third.y = fi.y; } else{third.x = se.x; third.y = se.y; }
//  out(third);Circle_Circle(first,second,fi,se);if ( fabs( dis(fi,third) - r )< 1e-6 ) ans = fi; else ans = se;
//  out(ans);}
int main()
{
//  freopen("in.txt","r",stdin);
//  freopen("out.txt","w",stdout);cin >> Test;while (Test--) {work();if (!bo){if ( same(p0,p1) ){a = l+m; b = n;ans.x = p0.x * b/(a+b) + p1.x *a/(a+b);ans.y = p0.y * b/(a+b) + p1.y *a/(a+b);} elseif ( same(p1,p2) ){a = m+n; b = a;ans.x = p1.x * b/(a+b) + p0.x *a/(a+b);ans.y = p1.y * b/(a+b) + p0.y *a/(a+b);} elseif ( same(p0,p2) ){a = l+n; b = m;ans.x = p0.x * b/(a+b) + p1.x *a/(a+b);ans.y = p0.y * b/(a+b) + p1.y *a/(a+b);}}fans = l*dis(p0,ans) + m*dis(p1,ans) + n*dis(p2,ans);fans = min( fans, m*dis(p1,p0) + n*dis(p2,p0));fans = min( fans, l*dis(p0,p1) + n*dis(p2,p1));fans = min( fans, l*dis(p0,p2) + m*dis(p1,p2));out(ans);printf("%.10lf\n",(double) fans);}system("pause");return 0;
}

转载于:https://www.cnblogs.com/LitIce/archive/2011/07/19/2111149.html

URAL1815 Farm in San Andreas(费马点,圆圆相交)相关推荐

  1. 欧拉定理 费马小定理

    前言 学基础数论的时候看过证明,然而很快就忘了,最近在学习高深一点的数论,于是再复习一下欧拉定理和费马小定理. 欧拉定理 内容 若正整数 \(a,n\) 互质,则 \(a^{\varphi(n)}\e ...

  2. 「欧拉定理」学习笔记(费马小定理)

    欧拉定理:对于互质的两个正整数$a, n$,满足$a^{φ(n)} ≡ 1\  (mod\ n)$ 证明: 设集合$S$包含所有$n$以内与$n$互质的数,共有$φ(n)$个:$$S = \{ x_1 ...

  3. 【ACM】杭电OJ 4704 Sum (隔板原理+组合数求和公式+费马小定理+快速幂)

    http://acm.hdu.edu.cn/showproblem.php?pid=4704 1.隔板原理 1~N有N个元素,每个元素代表一个1.分成K个数,即在(N-1)个空挡里放置(K-1)块隔板 ...

  4. 子段乘积(逆元费马小定理)+线段树做法

    题解:一开始做这个题的时候想过尺取法,但是因为没有逆元的知识,不知道该如何不断删除左端元素.其实这题并不难想,设l,r为两端开始都置为1,当长度小于k的时候不断乘右端元素并取余,当长度等于k时删除左端 ...

  5. 【学习笔记】高斯整数、高斯素数、费马平方和(全部相关概念及例题详解)《初等数论及其应用》

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 以下内容摘自 我的文章:算法竞赛中的数论问题 - 数论全家桶(信奥 / 数竞 / ACM)作者孟繁宇, ...

  6. luogu P2613 【模板】有理数取余(费马小定理,乘法逆元)

    整理的算法模板合集: ACM模板 目录 题目传送门 题目传送门 相当于是一个高精的费马小定理求乘法逆元.虽然数据达到了101000110^{10001}1010001,但是我们可以使用快读然后一直模m ...

  7. 关于素数常用结论--威尔逊定理、欧拉定理、费马小定理、米勒罗宾算法

    再需要判定的数比较大时,用枚举法肯定不行的,但目前数学界也没有任何一种又快又准确的判定素数的方法,并且也证明了素数不存在任何一种通项表达式.但作为初等数论中最大的一部分内容,数学家们对素数性质进行了大 ...

  8. 迷倒高斯、费马、欧拉的女王,竟是低调的她

    谁能想到,读一本书,能让人经历三次反转. 作为新媒体编辑,我总是能先人一步知道某本新书的动向:作者.内容.书名--而这本新出的<数学女王的邀请>,光名字就把我吓了一跳. 数学女王??谁?哪 ...

  9. 【BZOJ1951】【SDOI2010】古代猪文 Lucas定理、中国剩余定理、exgcd、费马小定理

    Description "在那山的那边海的那边有一群小肥猪.他们活泼又聪明,他们调皮又灵敏.他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心--" --选自猪王国民歌 很久 ...

最新文章

  1. 【SLAM】ORB-SLAM:让人Orz的SLAM
  2. 数据蒋堂 | 怎样生成有关联的测试数据
  3. linux中操作java进程
  4. like mysql 相反_mysql真的不能做搜索引擎吗?
  5. python的os模块批量获取目标路径下的文件名
  6. 可搜索本机文档内容软件:anytext(批量检索文档内容)(不是很好用,推荐用filelocator)
  7. Delphi中的各种路径
  8. 计算机二级c语言填空题怎么算分,计算机二级C语言题型和评分标准
  9. bzoj 3994 约数个数和 —— 反演+数论分块
  10. 阿里云商标注册服务及常见问题
  11. 几种流行Webservice框架性能对比(转载、拼接)
  12. 【LeetCode】第934题——最短的桥(难度:中等)
  13. uplift model的理论与实践
  14. 你好,C++(2)1.3 C++世界版图1.4 如何学好C++
  15. 程序设计考试大纲(高级程序员级)
  16. call()和appy()的区别及常用场景
  17. python3的所有标准库
  18. J2SE视频之面向对象——踏破铁鞋无觅处
  19. QQ互联第三方登录jar包
  20. css3之制作个性照片墙

热门文章

  1. SQL ROUND函数用法
  2. C++编程--函数与委托(2)
  3. 分享经验,让更多的人受益
  4. mysql char类型c 映射_使用Hibernate原生SQL映射MYSQL的CHAR(n)类型到String时出错
  5. 如何在Linux上部署Jenkins
  6. (22)Verilog HDL结构:function语句
  7. 查看函数说明_Axure函数使用说明
  8. 4mysql_12-4mysql 查询
  9. RTL8201EL介绍
  10. 【C语言】文件程序设计实践