HDU-4033 Fruit Ninja 几何 二分搜索
http://acm.hdu.edu.cn/showproblem.php?pid=4033
题中给定某一点到N个点的距离,问这些点能否组成正多边形?
思路:选定两条边,通过二分法枚举某一条边的边长,算出该边长下对应的中心角,然后再依据此边计算出其余三角形对应的中心角,最后看总的角度是否为360度。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
double e[200];
const double PI = 4 * atan( double( 1 ) );
int N;
double istri( double a, double b, double c )
{
if( c > a + b )
return 5;
else if( c < fabs( a - b ) )
return -5;
else
return acos( ( a * a + b * b - c * c ) / ( 2 * a * b ) );
}
double Acos( double a, double b, double c )
{
return istri( a, b, c );
}
double bs( double mid )
{
double ans = 0;
for( int i = 2; i <= N; ++i )
{
double t = Acos( e[i], e[i-1], mid );
if( fabs( t ) == 5 ) // 如果mid的这个取值使得某些相邻的两条边不
return t; // 能够形成三角形,则及时退出
else
ans += Acos( e[i], e[i-1], mid );
}
return ans;
// 最后返回总的角度大小
}
double bsearch( double ss, double ee )
{
double l = ss, r = ee, mid, sum_angle;
while( r - l >= 1e-9 )
{
mid = ( l + r ) / 2.0;
double t = bs( mid ); // 计算出一部分的角度总和
if( fabs( t ) == 5 )
{
if( t > 0 )
r = mid;
else
l = mid;
}
else
{
sum_angle = t + Acos( e[1] , e[N], mid );
if( sum_angle - 2 * PI > 1e-9 )
r = mid;
else if( sum_angle - 2 * PI < -1e-9 )
l = mid;
else
return mid;
}
}
return 0;
}
int main( )
{
int T;
scanf( "%d", &T );
for( int ca = 1; ca <= T; ++ca )
{
scanf( "%d", &N );
for( int i = 1; i <= N; ++i )
{
scanf( "%lf", &e[i] );
}
// 接下来选择第N条边以及第1条边来二分答案
// 根据三角形中有 C < A+B && C > A-B;
double ans = bsearch( fabs( e[N] - e[1] ), e[1] + e[N] );
printf( "Case %d: ", ca );
if( ans == 0 )
puts( "impossible" );
else
printf( "%.3lf\n", ans );
}
return 0;
}