hdu 4033 Regular Polygon

http://acm.hdu.edu.cn/showproblem.php?pid=4033

  这道题需要二分法求正多边形边长。

  题目给出正多边形内的一点与各个顶点间的连线线段长度,要求求出正多边形的边长,如果不存在这样的正多边形就输出impossible。

  由题目可以知道边长不会超过17320,所以就假设边长在(0, 20000)之间。然后,构造出计算当前状态的函数,再借助二分法来找到满足要求的点。这题的精度要求是精确到小数点后3位,不过要ac就必须将精度调至1e-6。计算当前状态的函数是要计算当边长为某个值的时候,所有相邻两条线的夹角和是否为2π。如果大于2π就缩小边长,否则就增大边长。

 

View Code
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <cstdlib>
 5 
 6 const int maxn = 101;
 7 const double pi = acos(-1.0);
 8 const double eps = 1e-6;
 9 double len[maxn];
10 
11 double cal(int n, double side){ // 二分收敛方向判定函数
12     double tmp = side * side;
13 
14     if (side > len[0] + len[n - 1]) return 4 * pi;
15     if (side < fabs(len[0] - len[n - 1])) return 0.0;
16 
17     double sum = acos((len[0] * len[0] + len[n - 1] * len[n - 1] - tmp) / (2 * len[0] * len[n - 1]));
18 
19     for (int i = 0; i < n - 1; i++){
20         if (side > len[i] + len[i + 1]) return 4 * pi;
21         if (side < fabs(len[i] - len[i + 1])) return 0.0;
22         sum += acos((len[i] * len[i] + len[i + 1] * len[i + 1] - tmp) / (2 * len[i] * len[i + 1]));
23     }
24 
25     return sum;
26 }
27 
28 double bs(int n){ // 二分法找出满足要求的边长
29     double h = 0.0;
30     double t = 20000.0;
31     double m, res;
32 
33     while (fabs(h - t) > eps){
34         m = (h + t) / 2.0;
35         res = cal(n, m);
36         if (res > 2.0 * pi) t = m;
37         else h = m;
38     }
39     if (fabs(cal(n, m) - 2 * pi) < 1e-4) return m; // 如果边长存在,则返回边长
40     else return 1e301; // 否则返回正无穷
41 }
42 
43 bool deal(int n, double &ans){
44     ans = bs(n);
45     if (ans > 1e300) return false;
46 /**下面这部分原打算是判断多边形是否严格满足要求,不过发现加上去以后就不能ac了。我觉得是hdu将菱形或其它的伪正多边形当作是正多边形来给出边长了**/
47 /*
48     if (n <= 3) return true;
49     double arc = 2.0 * pi / n;
50     double l = ans * 2.0 * cos(arc / 2);
51     double ang_a, ang_b ,ang_c;
52     for (int i = 0; i < n - 2; i++){
53         ang_a = acos((ans * ans - len[i] * len[i] - len[i + 1] * len[i + 1]) / (2 * len[i] * len[i + 1]));
54         ang_b = acos((ans * ans - len[i + 2] * len[i + 2] - len[i + 1] * len[i + 1]) / (2 * len[i + 2] * len[i + 1]));
55         ang_c = acos((l * l - len[i] * len[i] - len[i + 2] * len[i + 2]) / (2 * len[i] * len[i + 2]));
56         if (fabs(ang_c - ang_b - ang_a) > 1e-4) return false;
57     }
58 */
59     return true;
60 }
61 
62 int main(){
63 #ifndef ONLINE_JUDGE
64     freopen("in", "r", stdin);
65 #endif
66     int T, n;
67     double ans;
68 
69     scanf("%d", &T);
70     for (int i = 1; i <= T; i++){
71         scanf("%d", &n);
72         for (int j = 0; j < n; j++){
73             scanf("%lf", &len[j]);
74         }
75         printf("Case %d: ", i);
76         if (deal(n, ans)){
77             printf("%.3f\n", ans);
78         }
79         else{
80             printf("impossible\n");
81         }
82     }
83 
84     return 0;
85 }

 

——written by Lyon

 

转载于:https://www.cnblogs.com/LyonLys/archive/2012/08/23/hdu_4033_Lyon.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值