codeforces 1C(几何题)

http://codeforces.com/problemset/problem/1/C

  这是一道几何计算题。题目目的是:给出在一个正多边形上的三点,要求你求出这个正多边形最小的面积是多少。因为一个正多边形有且仅有一个外接圆,而且正多边形的所有点都在这个圆上,因此这个正多边形的半径是固定的,所以,如果希望这个正多边形的面积尽可能小,正多边形的边数就必须尽可能少。

  因此,题目转化为求正多边形的最少边数。这时,常规的做法是先求出外接圆的圆心,然后借助圆心和三个点得连线,将圆划分成三份,然后求三个圆心角的最大公约数。这个最大公约数就是圆等分切割后的每一份最大的圆心角,从而求出这个正多边形的最少边数。

  其中会遇到的问题就是怎么求几个带小数部分的数的最大公约数了。其实原理很简单,就是跟整数求最大公约数一样,辗转相除,用到函数fmod,但是其中小数部分精度的处理则需要特别关注的。由于题目要求的的最大边数只有100条,因此精度定位只需要到0.01,如果精度太高,对于这题来说,是百害而无一利的。因为高的精度只会导致求gcd后的结果过于精确,计算得出的边数可能会增加,因此,这题的精度只需要1e-2。

  然后就是代码:

View Code
  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

转载于:https://www.cnblogs.com/LyonLys/archive/2012/05/15/cf_1C_Lyon.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值