CF 1C Ancient Berland Circus

题目大意:平面上有三个点,属于一个正多边形的三个顶点。求该正多边形的最小面积。多边形的边数小于100。

题解:首先比较显然的是,若一个三角形存在多种正多边形满足,边数最少的正多边形一定面积最小。因此从小到大枚举边数,固定一个顶点,枚举另外两个顶点,看三角形是否与给出的三个点构成的三角形相似,若相似则可根据相似比求出整个正多边形的面积。外接圆的半径为 r 的正多边形的面积为nr22sin(2πn)
在判三角形相似的时候被精度坑了一发…

#include <bits/stdc++.h>

using namespace std;

const double eps = 1e-6;
const double pi = acos(-1.0);

struct node{
    double ang[3];
    bool operator==(const node &a){
        for(int i = 0;i < 3;i++){
            if(fabs(ang[i]-a.ang[i])>eps){
                return false;
            }
        }
        return true;
    }

};

struct Point{
    double x,y;
    Point(double a,double b):x(a),y(b){}
    Point(){}

    Point operator-(const Point &a) const{
        return Point(x-a.x,y-a.y);
    }

    Point operator+(const Point &a) const{
        return Point(x+a.x,y+a.y);
    }

    double operator^(const Point &a)const{
        return x*a.y-y*a.x;
    }

    double length2(){
        return x*x+y*y;
    }
    double length(){
        return sqrt(length2());
    }
};

typedef Point P;


node calc(P a,P b,P c){
    node ret;
    //printf("a x=%f y=%f\n",a.x,a.y);
    //printf("b x=%f y=%f\n",b.x,b.y);
    //printf("c x=%f y=%f\n",c.x,c.y);
    double t1,t2,t3;
    t1 = (a.length2()+b.length2()-c.length2())/(2*a.length()*b.length());
    t2 = (a.length2()+c.length2()-b.length2())/(2*a.length()*c.length());
    t3 = (c.length2()+b.length2()-a.length2())/(2*c.length()*b.length());
   // printf("%f\n%f\n%f\n",t1,t2,t3);
    ret.ang[0] = acos(t1);
    ret.ang[1] = acos(t2);
    ret.ang[2] = acos(t3);
    sort(ret.ang,ret.ang+3);
    return ret;
}

double area(P a,P b){
    return 0.5*fabs(a^b);
}

Point points[150];

int main(){
    P p[3];
    for(int i = 0;i < 3;i++){
        scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    node tri = calc(p[0]-p[1],p[1]-p[2],p[2]-p[0]);
    double are = area(p[0]-p[1],p[1]-p[2]);
    double ans = 0;
    bool flag = false;
    //printf("are=%f\n",are);
    //for(int i = 0;i < 3;i++){
    //    printf("ang%d = %f\n",i,tri.ang[i]);
    //}
    for(int i = 3;i <= 100;i++){
        double totare = 1.0*i*sin(2*pi/i)/2;
        for(int j = 0;j < i;j++){
            double x,y,sita;
            sita = 2*pi/i*j;
            x = 1.0*sin(sita);
            y = 1.0*cos(sita);
            points[j] = Point(x,y);
        }
        for(int j = 1;j < i;j++){
            for(int k = j+1;k < i;k++){
                node tmp = calc(points[0]-points[j],points[j]-points[k],points[k]-points[0]);
                //if(i == 6&&j == 2&&k == 3){
                //    printf("%f %f %f\n",tmp.ang[0],tmp.ang[1],tmp.ang[2]);
                //}
                if(tmp == tri){
                    double ta = area(points[0]-points[j],points[j]-points[k]);
                    ans = are/ta*totare;
                    flag = true;
                    break;
                }
            }
            if(flag) break;
        }
        if(flag) break;
    }
    printf("%.8f\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值