http://codeforces.com/problemset/problem/1/C
这是一道几何计算题。题目目的是:给出在一个正多边形上的三点,要求你求出这个正多边形最小的面积是多少。因为一个正多边形有且仅有一个外接圆,而且正多边形的所有点都在这个圆上,因此这个正多边形的半径是固定的,所以,如果希望这个正多边形的面积尽可能小,正多边形的边数就必须尽可能少。
因此,题目转化为求正多边形的最少边数。这时,常规的做法是先求出外接圆的圆心,然后借助圆心和三个点得连线,将圆划分成三份,然后求三个圆心角的最大公约数。这个最大公约数就是圆等分切割后的每一份最大的圆心角,从而求出这个正多边形的最少边数。
其中会遇到的问题就是怎么求几个带小数部分的数的最大公约数了。其实原理很简单,就是跟整数求最大公约数一样,辗转相除,用到函数fmod,但是其中小数部分精度的处理则需要特别关注的。由于题目要求的的最大边数只有100条,因此精度定位只需要到0.01,如果精度太高,对于这题来说,是百害而无一利的。因为高的精度只会导致求gcd后的结果过于精确,计算得出的边数可能会增加,因此,这题的精度只需要1e-2。
然后就是代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "cstdio" 2 #include "cstdlib" 3 #include "cstring" 4 #include "cmath" 5 #include "cctype" 6 #include "vector" 7 #include "set" 8 #include "map" 9 #include "string" 10 #include "algorithm" 11 #include "stack" 12 #include "queue" 13 14 #define INF 0x7fffffff 15 #define reset(a) memset(a, 0, sizeof(a)) 16 #define copy(a, b) memcpy(a, b, sizeof(b)) 17 #define FMAX (1E300) 18 #define MAX 1000000000 19 #define feq(a, b) (fabs((a)-(b))<1E-2) 20 #define flq(a, b) ((a)<(b)||feq(a, b)) 21 #define MAXN 10005 22 #define BASE 137 23 #define PASS puts("pass") 24 #define filein freopen("test.in", "r", stdin) 25 #define fileout freopen("test.out", "w", stdout) 26 27 using namespace std; 28 const double PI = acos(-1); 29 30 struct Point{ 31 double x; 32 double y; 33 }; 34 35 void swap(double &a, double &b){ 36 double t; 37 t = a; 38 a = b; 39 b = t; 40 } 41 42 bool find_center(Point *p, Point &c){ 43 //存在外接圆返回true,否则返回false 44 double dx1 = p[1].x - p[0].x; 45 double dy1 = p[1].y - p[0].y; 46 double dx2 = p[2].x - p[0].x; 47 double dy2 = p[2].y - p[0].y; 48 49 if (feq(dx1 * dx2 + dy1 * dy2, 0)){ 50 c.x = (p[1].x + p[2].x) / 2; 51 c.y = (p[1].y + p[2].y) / 2; 52 53 return true; 54 } 55 if (feq(dx1 * dy2, dx2 * dy1)) 56 return false; 57 58 double mx1 = (p[1].x + p[0].x) / 2; 59 double my1 = (p[1].y + p[0].y) / 2; 60 double mx2 = (p[2].x + p[0].x) / 2; 61 double my2 = (p[2].y + p[0].y) / 2; 62 double a1 = dx1, b1 = dy1, c1 = - mx1 * dx1 - my1 * dy1; 63 double a2 = dx2, b2 = dy2, c2 = - mx2 * dx2 - my2 * dy2; 64 65 c.x = (c1 * b2 - c2 * b1) / (a2 * b1 - a1 * b2); 66 c.y = (c1 * a2 - c2 * a1) / (a1 * b2 - a2 * b1); 67 /** 68 printf("%.6f %.6f\n", c.x, c.y); 69 printf("a1 %.6f b1 %.6f c1 %.6f\n", a1, b1, c1); 70 printf("a2 %.6f b2 %.6f c2 %.6f\n", a2, b2, c2); 71 /**/ 72 return true; 73 } 74 75 double fgcd(double a, double b){ 76 //带小数的两个数求最大公约数 77 if (feq(a, 0)) 78 return b; 79 if (feq(b, 0)) 80 return a; 81 return fgcd(b, fmod(a, b)); 82 } 83 84 int main(){ 85 Point tri[4]; 86 87 //filein; 88 //fileout; 89 while (1){ 90 for (int i = 1; i <= 3; i++){ 91 if (!~scanf("%lf%lf", &tri[i].x, &tri[i].y)) 92 return 0; 93 } 94 find_center(&tri[1], tri[0]); 95 /** 96 if (find_center(&tri[1], tri[0])){ 97 printf("Exist!\nx = %10.6f y = %10.6f\n", tri[0].x, tri[0].y); 98 } 99 else printf("Not exist!\n"); 100 /**求出三角形三条边的长度**/ 101 double r = sqrt((tri[1].x - tri[0].x) * (tri[1].x - tri[0].x) 102 + (tri[1].y - tri[0].y) * (tri[1].y - tri[0].y)); 103 double l1 = sqrt((tri[2].x - tri[3].x) * (tri[2].x - tri[3].x) 104 + (tri[2].y - tri[3].y) * (tri[2].y - tri[3].y)); 105 double l2 = sqrt((tri[1].x - tri[3].x) * (tri[1].x - tri[3].x) 106 + (tri[1].y - tri[3].y) * (tri[1].y - tri[3].y)); 107 double l3 = sqrt((tri[1].x - tri[2].x) * (tri[1].x - tri[2].x) 108 + (tri[1].y - tri[2].y) * (tri[1].y - tri[2].y)); 109 /**对三条边的长度排序,从而得到最短的两条边**/ 110 if (l3 < l1){ 111 swap(l1, l3); 112 } 113 if (l3 < l2){ 114 swap(l2, l3); 115 } 116 //printf("\nl1 %.6f l2 %.6f l3 %.6f r %.6f\n", l1, l2, l3, r); 117 /**求出圆心角**/ 118 double angle1 = acos(1 - (l1 / r) * (l1 / r) / 2) * 180/ PI; 119 double angle2 = acos(1 - (l2 / r) * (l2 / r) / 2) * 180 / PI; 120 double angle3 = 360 - angle1 - angle2; 121 double e = 360 / fgcd(angle1, fgcd(angle2, angle3)); 122 123 /** 124 printf("a1 %.6f a2 %.6f a3 %.6f\n", angle1, angle2, angle3); 125 printf("%.6f\n", fgcd(angle1, fgcd(angle2, angle3))); 126 printf("%.6f\n", e); 127 /**/ 128 129 double angle = 360 / e; 130 131 printf("%.8f\n", sin(angle * PI / 180) * r * r * e / 2); 132 } 133 }
作为一个ACMer,我觉得这些数学题的学习是十分必要的。
——written by Lyon