题目分析:首先要求凸包是毫无疑问的,任意两点之间有边则如果内部有边与平行线相交则最外面一定有边与平行线相交。
重点是求概率。
由概率论书上什么抛针问题(我也不懂)可知一条长度为L的线段与间距为D的平行线相交的概率为2L / πD,由此我们可知凸包上一条线段Li与间距为D的平行线相交的概率为2Li / πD,又因为凸包上如果有一条线段与平行线相交则必定存在另一条线段Lj与Li同时与平行线相交(凸包是封闭凸多边形),那么2Li / πD = ∑Pij(Pij表示Li与Lj同时与平行线相交的概率,同时i!=j),则凸包与平行线相交的概率为1 / 2 * sum{ sum{ Pij | i != j } | 1 <= i <= n },除以2的原因是Pij与Pji是等价的,是同时满足的。
那么问题最后就转化成了求凸包的周长了。这个就很简单了,也就不说了。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define REP( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define REV( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define CLR( a , x ) memset ( a , x , sizeof a )
#define CPY( a , x ) memcpy ( a , x , sizeof a )
const int MAXN = 100 ;
struct Point {
double x , y ;
Point () {}
Point ( double x , double y ) : x ( x ) , y ( y ) {}
Point operator - ( const Point& a ) const {
return Point ( x - a.x , y - a.y ) ;
}
bool operator < ( const Point& a ) const {
return x != a.x ? x < a.x : y < a.y ;
}
void input () {
scanf ( "%lf%lf" , &x , &y ) ;
}
} p[MAXN] ;
int n , D ;
int S[MAXN] , top ;
double cross ( const Point& a , const Point& b ) {
return a.x * b.y - a.y * b.x ;
}
double dist ( const Point& a ) {
return sqrt ( a.x * a.x + a.y * a.y ) ;
}
void convex_hull ( Point p[] , int n ) {
top = 0 ;
sort ( p , p + n ) ;
REP ( i , 0 , n ) {
while ( top > 1 && cross ( p[i] - p[S[top - 2]] , p[S[top - 1]] - p[S[top - 2]] ) >= 0 ) -- top ;
S[top ++] = i ;
}
int k = top ;
REV ( i , n - 2 , 0 ) {
while ( top > k && cross ( p[i] - p[S[top - 2]] , p[S[top - 1]] - p[S[top - 2]] ) >= 0 ) -- top ;
S[top ++] = i ;
}
}
void solve () {
double L = 0 ;
scanf ( "%d%d" , &n , &D ) ;
REP ( i , 0 , n ) p[i].input () ;
convex_hull ( p , n ) ;
REP ( i , 1 , top ) L += dist ( p[S[i]] - p[S[i - 1]] ) ;
printf ( "%.4f\n" , L / acos ( -1.0 ) / D ) ;
}
int main () {
int T , cas = 0 ;
scanf ( "%d" , &T ) ;
while ( T -- ) {
printf ( "Case #%d: " , ++ cas ) ;
solve () ;
}
return 0 ;
}