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