利用余弦定理,构造函数 b=sigma(acos(a[i]^2+a[i+1]^2-e^2)/(2a[i]a[i+1]))。e为边长。当e为解时,b=2*pi(内角和)。重点是,b(e)是单调上升的。所以可以二分。(事实上我觉得这种题目必然要二分,重点就是找一个单调函数)。
写的时候,犯了个很傻逼的错误,还以为是精度问题,就一直改精度........(我发现其实做eps的精度,就把eps对应成整数里的1来理解就是了,二分、比较大小什么的都是跟整数同理的,这样好想很多)。 改到我觉得精度不可能有问题的时候...........突然发现,原来我开始的上下界写错了。竟然把 +-eps写到循环里了.......还有,这题是maxe=min(a[i]+a[i+1]),mine=max(fabs(a[i]-a[i+1])) 的.......这里写的时候也傻逼了。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> using namespace std; #define MAXN 110 #define INF 1<<30 #define pi acos(-1.0) #define eps 1e-8 //eps !! double a[MAXN]; //边长 int n; double f(double x1, double x2, double e) //返回角度 { return acos((x1*x1+x2*x2-e*e)/(2*x1*x2)); } double func(double e) // f(边长)-> 2pi { double ret=0; for(int i=0; i<n; i++) { int j=(i+1)%n; ret+=f(a[i], a[j], e); } return ret; } int cmp(double x, double y) { if(fabs(x-y)<eps) return 0; // else if(x>=y+eps) return 1; //x>=y+eps else return -1; } double solve() { double maxe=INF, mine=0; //① 很容易错,因为max值是取min操作的........ for(int i=0; i<n; i++) { int j=(i+1)%n; // maxe = max(maxe, a[i]+a[j])-eps; //!!!! 傻逼 // mine = min(mine, fabs(a[i]-a[j]))+eps; //maxe = max(maxe, a[i]+a[j]); //!!!傻逼,too //mine = min(mine, fabs(a[i]-a[j])); maxe = min(maxe, a[i]+a[j]); mine = max(mine, fabs(a[i]-a[j])); } double l=mine+eps, r=maxe-eps; int yes=0; //防止一直处于 l=r while(r-l>eps || !cmp(r, l)) //相当于eps精度下的 l<=r { double mid=(l+r)/2; double t = func(mid); //printf("t=%lf, 2*pi=%lf, sub=%.10lf\n", t, 2*pi, fabs(t-2*pi)); int flag = cmp(t, 2*pi); if(!flag) return mid; else if(flag>0) r=mid-eps; else if(flag<0) l=mid+eps; //printf("(%.10lf, %.10lf), sub=%.10lf, eps=%.10lf\n", l, r, r-l, eps); if(yes) break; if(!cmp(l, r)) yes=1; } return 0; } int main() { int t; scanf("%d", &t); for(int T=0; T<t; T++) { printf("Case %d: ", T+1); scanf("%d", &n); for(int i=0; i<n; i++) { scanf("%lf", &a[i]); } double t = solve(); if(t) printf("%.3lf\n", t); else printf("impossible\n"); } }