题目大意:给一个简单多边形,每次只能从多边形上编号
i
的点到编号
题目分析:要知道多边形的边只会在端点相交。则如果以一个点为原点,作射线,然后旋转,那么遇到边的左端点我们往set插入线段,遇到边的右端点我们删除线段,那么任意时刻在set中的线段和射线的交点到原点的距离的大小关系是相对不变的。那么我们就可以通过动态维护set的操作符’<’动态维护线段距离原点的远近了。
接下来就很简单了,枚举原点,然后极角排序,然后转转转,对每个极角序下距离原点最近的点看看有没有线段严格相交(相交且端点不在线段上)即可。
Hint:要注意仔细看题面!!两端点之间只能走直线,走出的线段上不能有多边形的其他端点且不能和多边形严格相交(我就是没注意到这句话以为能走曲线,所以死活过不了,mdzz)。
#include <bits/stdc++.h>
using namespace std ;
typedef pair < int , int > pii ;
typedef long long LL ;
#define clr( a , x ) memset ( a , x , sizeof a )
const int MAXN = 1005 ;
const double eps = 1e-8 ;
const double pi = acos ( -1.0 ) ;
struct Point {
double x , y ;
Point () {}
Point ( double x , double y ) : x ( x ) , y ( y ) {}
Point operator - ( const Point& p ) const {
return Point ( x - p.x , y - p.y ) ;
}
Point operator + ( const Point& p ) const {
return Point ( x + p.x , y + p.y ) ;
}
Point operator * ( const double& v ) const {
return Point ( x * v , y * v ) ;
}
double operator * ( const Point& p ) const {
return x * p.y - y * p.x ;
}
double cdot ( Point p ) {
return x * p.x + y * p.y ;
}
double len () {
return sqrt ( x * x + y * y ) ;
}
double angle () {
return atan2 ( y , x ) ;
}
} ;
Point s , t ;
int sgn ( double x ) {
if ( fabs ( x ) < eps ) return 0 ;
return x > eps ? 1 : -1 ;
}
struct Segment {
Point u , v ;
int idx ;
bool operator < ( const Segment& l ) const {
double U1 = ( u - s ) * ( v - u ) ;
double D1 = ( t - s ) * ( v - u ) ;
double U2 = ( l.u - s ) * ( l.v - l.u ) ;
double D2 = ( t - s ) * ( l.v - l.u ) ;
double dis1 = U1 / D1 ;
double dis2 = U2 / D2 ;
if ( sgn ( dis1 - dis2 ) ) return dis1 < dis2 ;
return idx < l.idx ;
}
} ;
struct Node {
double r , d ;
int idx ;
Node () {}
Node ( double r , int idx , int d = 0 ) : r ( r ) , idx ( idx ) , d ( d ) {}
bool operator < ( const Node& a ) const {
if ( sgn ( r - a.r ) ) return r < a.r ;
if ( sgn ( d - a.d ) ) return d < a.d ;
return idx < a.idx ;
}
} ;
Node a[MAXN] , b[MAXN << 1] ;
Segment seg[MAXN] ;
Point p[MAXN] ;
set < Segment > S ;
set < Segment > :: iterator it ;
double dis[MAXN][MAXN] , dp[MAXN] , val[MAXN] ;
double rl[MAXN] , rr[MAXN] ;
int G[MAXN][MAXN] , vis[MAXN] ;
int n , cnt ;
int has_intersection ( Point a , Point b , Point p , Point q ) {
int d1 = sgn ( ( b - a ) * ( p - a ) ) ;
int d2 = sgn ( ( b - a ) * ( q - a ) ) ;
int d3 = sgn ( ( q - p ) * ( a - p ) ) ;
int d4 = sgn ( ( q - p ) * ( b - p ) ) ;
if ( d1 * d2 < 0 && d3 * d4 < 0 ) return 1 ;
return 0 ;
}
bool check () {
if ( S.begin () == S.end () ) return 1 ;
it = S.begin () ;
return has_intersection ( s , t , it->u , it->v ) == 0 ;
}
void calc ( int idx , int m ) {
sort ( a , a + m ) ;
S.clear () ;
int q = 0 ;
s = p[idx] ;
t = s + Point ( 1e6 , 0 ) ;
for ( int i = 0 ; i < cnt ; ++ i ) {
if ( sgn ( ( seg[i].u - s ) * ( seg[i].v - s ) ) ) {
vis[i] = 0 ;
double r1 = ( seg[i].u - s ).angle () ;
double r2 = ( seg[i].v - s ).angle () ;
if ( r1 > r2 ) swap ( r1 , r2 ) ;
if ( has_intersection ( s , t , seg[i].u , seg[i].v ) == 1 ) {
b[q ++] = Node ( r1 , i ) ;
b[q ++] = Node ( r2 , i ) ;
} else {
if ( r1 < 0 && r2 < 0 ) continue ;
if ( r1 < 0 && r2 > 0 ) {
r1 += 2 * pi ;
swap ( r1 , r2 ) ;
}
b[q ++] = Node ( r1 , i ) ;
b[q ++] = Node ( r2 , i ) ;
}
}
}
sort ( b , b + q ) ;
int j = 0 ;
for ( int i = 0 ; i < m ; ++ i ) {
int idi = a[i].idx ;
t = p[idi] ;
while ( j < q && sgn ( a[i].r - b[j].r ) >= 0 ) {
int o = b[j ++].idx ;
if ( !vis[o] ) S.insert ( seg[o] ) ;
else S.erase ( seg[o] ) ;
vis[o] ^= 1 ;
}
if ( i && sgn ( a[i].r - a[i - 1].r ) == 0 ) continue ;
double tmpr = a[i].r ;
if ( ( sgn ( rl[idx] - tmpr ) < 0 && sgn ( tmpr - rr[idx] ) < 0 ) ) continue ;
if ( tmpr < 0 ) tmpr += 2 * pi ;
if ( ( sgn ( rl[idx] - tmpr ) < 0 && sgn ( tmpr - rr[idx] ) < 0 ) ) continue ;
tmpr = a[i].r - pi ;
if ( ( sgn ( rl[idi] - tmpr ) < 0 && sgn ( tmpr - rr[idi] ) < 0 ) ) continue ;
if ( tmpr < 0 ) tmpr += 2 * pi ;
if ( ( sgn ( rl[idi] - tmpr ) < 0 && sgn ( tmpr - rr[idi] ) < 0 ) ) continue ;
if ( check () ) G[idx][idi] = G[idi][idx] = 1 ;
}
}
void solve () {
scanf ( "%d" , &n ) ;
for ( int i = 0 ; i < n ; ++ i ) {
scanf ( "%lf%lf%lf" , &p[i].x , &p[i].y , &val[i] ) ;
}
cnt = n ;
for ( int i = 0 ; i < n ; ++ i ) {
int j = ( i + 1 ) % n , k = ( i + 2 ) % n ;
rl[j] = ( p[k] - p[j] ).angle () ;
rr[j] = ( p[i] - p[j] ).angle () ;
if ( rl[j] > rr[j] ) rr[j] += 2 * pi ;
seg[i].idx = i ;
seg[i].u = p[i] ;
seg[i].v = p[j] ;
}
for ( int i = 0 ; i < n ; ++ i ) {
for ( int j = i ; j < n ; ++ j ) {
G[i][j] = G[j][i] = 0 ;
dis[i][j] = dis[j][i] = ( p[j] - p[i] ).len () ;
}
}
for ( int i = 0 ; i < n ; ++ i ) {
int m = 0 ;
for ( int j = 0 ; j < n ; ++ j ) {
if ( p[j].y > p[i].y || p[j].y == p[i].y && j > i ) {
a[m ++] = Node ( ( p[j] - p[i] ).angle () , j , dis[i][j] ) ;
}
}
calc ( i , m ) ;
}
double ans = dp[0] = val[0] ;
for ( int i = 1 ; i < n ; ++ i ) {
dp[i] = -1e50 ;
for ( int j = 0 ; j < i ; ++ j ) {
if ( G[i][j] ) dp[i] = max ( dp[i] , dp[j] - dis[i][j] ) ;
}
dp[i] += val[i] ;
ans = max ( ans , dp[i] ) ;
}
printf ( "%.8f\n" , ans ) ;
}
int main () {
int T ;
scanf ( "%d" , &T ) ;
for ( int i = 1 ; i <= T ; ++ i ) {
printf ( "Case #%d: " , i ) ;
solve () ;
}
return 0 ;
}
看错题,以为两点间能走曲线,写了以下代码,最后才发现看错题了……
考虑多边形的凹点,将两侧的边沿边的方向,向内部延伸0.5;凸点则取点向两侧边上延伸0.5的点然后连接。同时记录以每个点为转轴,多边形所覆盖的极角区间。
为了方便,上述延伸只延伸0.5,延伸0.5只是一个估计,猜测这样不会和其他线段相交,可以改成数学推导。
写到最后死活过不了才发现是看错题,其实上面的代码加一个“直线上所有点的求连通”也就可以处理可走曲线的情况了。
以下是看错题,以为两端点之间能走曲线的时候的代码:
#include <bits/stdc++.h>
using namespace std ;
typedef pair < int , int > pii ;
typedef long long LL ;
#define clr( a , x ) memset ( a , x , sizeof a )
const int MAXN = 1005 ;
const double eps = 1e-8 ;
const double pi = acos ( -1.0 ) ;
struct Point {
double x , y ;
Point () {}
Point ( double x , double y ) : x ( x ) , y ( y ) {}
Point operator - ( const Point& p ) const {
return Point ( x - p.x , y - p.y ) ;
}
Point operator + ( const Point& p ) const {
return Point ( x + p.x , y + p.y ) ;
}
Point operator * ( const double& v ) const {
return Point ( x * v , y * v ) ;
}
double operator * ( const Point& p ) const {
return x * p.y - y * p.x ;
}
double cdot ( Point p ) {
return x * p.x + y * p.y ;
}
double len () {
return sqrt ( x * x + y * y ) ;
}
double angle () {
return atan2 ( y , x ) ;
}
} ;
Point s , t ;
int sgn ( double x ) {
if ( fabs ( x ) < eps ) return 0 ;
return x > eps ? 1 : -1 ;
}
struct Segment {
Point u , v ;
int idx ;
bool operator < ( const Segment& l ) const {
double U1 = ( u - s ) * ( v - u ) ;
double D1 = ( t - s ) * ( v - u ) ;
double U2 = ( l.u - s ) * ( l.v - l.u ) ;
double D2 = ( t - s ) * ( l.v - l.u ) ;
double dis1 = U1 / D1 ;
double dis2 = U2 / D2 ;
if ( sgn ( dis1 - dis2 ) ) return dis1 < dis2 ;
return idx < l.idx ;
}
} ;
struct Node {
double r ;
int idx , f ;
Node () {}
Node ( double r , int idx , int f = 0 ) : r ( r ) , idx ( idx ) , f ( f ) {}
bool operator < ( const Node& a ) const {
if ( sgn ( r - a.r ) ) return r < a.r ;
return f > a.f ;
}
} ;
Node a[MAXN] , b[MAXN << 2] ;
Segment seg[MAXN << 1] ;
Point p[MAXN] ;
set < Segment > S ;
double dis[MAXN][MAXN] , dp[MAXN] , val[MAXN] ;
double rl[MAXN] , rr[MAXN] ;
int vis[MAXN << 1] ;
int n , cnt ;
int face ;
double area () {
double ans = 0 ;
for ( int i = 0 ; i < n ; ++ i ) {
ans += p[i] * p[( i + 1 ) % n] ;
}
return ans ;
}
int Face ( int i , int j , int k ) {
return sgn ( ( p[j] - p[i] ) * ( p[k] - p[i] ) ) ;
}
bool point_on_segment ( Point& p , Point& a , Point& b ) {
return sgn ( ( b - a ) * ( p - a ) ) == 0 && sgn ( ( p - a ).cdot ( p - b ) ) <= 0 ;
}
int has_intersection ( Point& a , Point& b , Point& p , Point& q ) {
int d1 = sgn ( ( b - a ) * ( p - a ) ) ;
int d2 = sgn ( ( b - a ) * ( q - a ) ) ;
int d3 = sgn ( ( q - p ) * ( a - p ) ) ;
int d4 = sgn ( ( q - p ) * ( b - p ) ) ;
if ( d1 * d2 < 0 && d3 * d4 < 0 ) return 1 ;
if ( ( !d1 && point_on_segment ( p , a , b ) ) ||
( !d2 && point_on_segment ( q , a , b ) ) ||
( !d3 && point_on_segment ( a , p , q ) ) ||
( !d4 && point_on_segment ( b , p , q ) ) ) return -1 ;
return 0 ;
}
int line_intersection ( Point a , Point b , Point p , Point q , Point& o , double& t ) {
double U = ( p - a ) * ( q - p ) ;
double D = ( b - a ) * ( q - p ) ;
if ( fabs ( D ) < eps ) return fabs ( U ) < eps ? 2 : 0 ;
o = a + ( b - a ) * ( U / D ) ;
t = U / D ;
return 1 ;
}
Point crosspoint ( Point u , Point v , int idx ) {
Point res = v ;
double dis = ( v - u ).len () , t ;
Point o ;
for ( int i = 0 ; i < n ; ++ i ) {
int j = ( i + 1 ) % n ;
if ( i == idx || j == idx ) continue ;
if ( i == idx - 1 || j == idx - 1 ) continue ;
if ( has_intersection ( u , v , p[i] , p[j] ) == 0 ) continue ;
int cross = line_intersection ( u , v , p[i] , p[j] , o , t ) ;
if ( !cross ) continue ;
if ( cross == 2 ) {
if ( ( v - u ).cdot ( p[i] - u ) > eps ) {
double tmp = ( p[i] - u ).len () ;
if ( tmp < dis ) dis = tmp , res = p[i] ;
}
if ( ( v - u ).cdot ( p[j] - u ) > eps ) {
double tmp = ( p[j] - u ).len () ;
if ( tmp < dis ) dis = tmp , res = p[j] ;
}
} else {
if ( t < eps ) continue ;
double tmp = ( o - u ).len () ;
if ( tmp < dis ) dis = tmp , res = o ;
}
}
return res ;
}
bool check ( int x , int y ) {
if ( S.begin () == S.end () ) return 1 ;
Segment it = *S.begin () ;
return has_intersection ( s , t , it.u , it.v ) <= 0 ;
}
void calc ( int idx , int m ) {
sort ( a , a + m ) ;
S.clear () ;
int q = 0 ;
s = p[idx] ;
t = s + ( p[a[0].idx] - s ) * 1e6 ;
for ( int i = 0 ; i < cnt ; ++ i ) {
if ( sgn ( ( seg[i].u - s ) * ( seg[i].v - s ) ) ) {
vis[i] = 0 ;
double r1 = ( seg[i].u - s ).angle () ;
double r2 = ( seg[i].v - s ).angle () ;
if ( r1 > r2 ) swap ( r1 , r2 ) ;
if ( has_intersection ( s , t , seg[i].u , seg[i].v ) > 0 ) {
S.insert ( seg[i] ) ;
b[q ++] = Node ( r1 , i , 1 ) ;
b[q ++] = Node ( r2 , i , 0 ) ;
} else {
b[q ++] = Node ( r1 , i , 0 ) ;
b[q ++] = Node ( r2 , i , 1 ) ;
}
}
}
//for ( set < Segment > :: iterator it = S.begin () ; it != S.end () ; ++ it ) {
// if ( idx == 4 ) printf ( "out seg = %d\n" , it->idx ) ;
//}
sort ( b , b + q ) ;
int j = 0 ;
while ( j < q ) {
int f = sgn ( a[0].r - b[j].r ) ;
if ( f < 0 || !f && b[j].f == 0 ) break ;
++ j ;
}
for ( int i = 0 ; i < m ; ++ i ) {
int idi = a[i].idx ;
t = p[idi] ;
while ( j < q ) {
int f = sgn ( a[i].r - b[j].r ) ;
if ( f < 0 || !f && b[j].f == 0 ) break ;
int o = b[j].idx ;
if ( !vis[o] ) S.insert ( seg[o] ) ;
else S.erase ( seg[o] ) ;
vis[o] ^= 1 ;
//if ( idx == 4 ) printf ( "-----j = %d seg = %d r = %.3f\n" , j , o , b[j].r ) ;
++ j ;
}
//for ( set < Segment > :: iterator it = S.begin () ; it != S.end () ; ++ it ) {
//if ( idx == 4 && idi == 7 ) printf ( "seg = %d\n" , it->idx ) ;
//}
double tmpr = a[i].r ;
//if ( idx == 5 && idi == 7 ) printf ( "idx = %d , idi = %d , rl = %.3f , rr = %.3f , tmpr = %.3f\n" , idx , idi , rl[idx] , rr[idx] , tmpr ) ;
if ( ( sgn ( rl[idx] - tmpr ) < 0 && sgn ( tmpr - rr[idx] ) < 0 ) ) continue ;
if ( tmpr < 0 ) tmpr += 2 * pi ;
if ( ( sgn ( rl[idx] - tmpr ) < 0 && sgn ( tmpr - rr[idx] ) < 0 ) ) continue ;
tmpr = a[i].r - pi ;
//if ( idx == 5 && idi == 7 ) printf ( "idx = %d , idi = %d , rl = %.3f , rr = %.3f , tmpr = %.3f\n" , idx , idi , rl[idx] , rr[idx] , tmpr ) ;
if ( ( sgn ( rl[idi] - tmpr ) < 0 && sgn ( tmpr - rr[idi] ) < 0 ) ) continue ;
if ( tmpr < 0 ) tmpr += 2 * pi ;
if ( ( sgn ( rl[idi] - tmpr ) < 0 && sgn ( tmpr - rr[idi] ) < 0 ) ) continue ;
if ( check ( idx , idi ) ) dis[idx][idi] = dis[idi][idx] = ( t - s ).len () ;
//if ( check ( idx , idi ) ) dis[idx][idi] = dis[idi][idx] = ( t - s ).len () ;
}
}
void solve () {
scanf ( "%d" , &n ) ;
for ( int i = 0 ; i < n ; ++ i ) {
scanf ( "%lf%lf%lf" , &p[i].x , &p[i].y , &val[i] ) ;
}
double sum = area () ;
if ( sgn ( sum ) < 0 ) {
for ( int i = 0 ; i < n / 2 ; ++ i ) {
swap ( p[i] , p[n - i - 1] ) ;
swap ( val[i] , val[n - i - 1] ) ;
}
}
for ( int i = 0 ; i < n ; ++ i ) {
seg[i].idx = i ;
int j = ( i + 1 ) % n , k = ( i + 2 ) % n ;
rl[j] = ( p[k] - p[j] ).angle () ;
rr[j] = ( p[i] - p[j] ).angle () ;
if ( rl[j] > rr[j] ) rr[j] += 2 * pi ;
//printf ( "%.2f %.2f\n" , rl[j] , rr[j] ) ;
int f = Face ( i , j , k ) ;
if ( !f ) {
seg[i].v = p[k] ;
seg[j].u = p[i] ;
} else if ( f < 0 ) {
double r1 = ( p[j] - p[i] ).angle () ;
double r2 = ( p[j] - p[k] ).angle () ;
Point x = p[i] + Point ( 0.5 * cos ( r1 ) , 0.5 * sin ( r1 ) ) ;
Point y = p[k] + Point ( 0.5 * cos ( r2 ) , 0.5 * sin ( r2 ) ) ;
seg[i].v = x ;
seg[j].u = y ;
} else {
seg[i].v = p[j] ;
seg[j].u = p[j] ;
}
}
cnt = n ;
for ( int i = 0 ; i < n ; ++ i ) {
int j = ( i + 1 ) % n , k = ( i + 2 ) % n ;
int f = Face ( i , j , k ) ;
if ( f == 1 ) {
double r1 = ( p[i] - p[j] ).angle () ;
double r2 = ( p[k] - p[j] ).angle () ;
Point x = p[j] + Point ( 0.5 * cos ( r1 ) , 0.5 * sin ( r1 ) ) ;
Point y = p[j] + Point ( 0.5 * cos ( r2 ) , 0.5 * sin ( r2 ) ) ;
seg[cnt].idx = cnt ;
seg[cnt].u = x ;
seg[cnt].v = y ;
cnt ++ ;
}
}
for ( int i = 0 ; i < cnt ; ++ i ) {
//printf ( "idx = %d , %.5f %.5f %.5f %.5f\n" , i , seg[i].u.x , seg[i].u.y , seg[i].v.x , seg[i].v.y ) ;
}
for ( int i = 0 ; i < n ; ++ i ) {
for ( int j = 0 ; j < n ; ++ j ) {
dis[i][j] = 1e10 ;
}
}
for ( int i = 0 ; i < n ; ++ i ) {
int m = 0 ;
for ( int j = 0 ; j < n ; ++ j ) {
if ( p[j].y > p[i].y || p[j].y == p[i].y && j > i ) a[m ++] = Node ( ( p[j] - p[i] ).angle () , j ) ;
}
calc ( i , m ) ;
}
for ( int i = 0 ; i < n ; ++ i ) {
for ( int j = i + 1 ; j < n ; ++ j ) {
//printf ( "dp[%d][%d] = %.5f\n" , i , j , dis[i][j] ) ;
}
}
dp[0] = val[0] ;
double ans = dp[0] ;
for ( int i = 1 ; i < n ; ++ i ) {
dp[i] = -1e50 ;
for ( int j = 0 ; j < i ; ++ j ) {
dp[i] = max ( dp[i] , dp[j] - dis[j][i] ) ;
}
dp[i] += val[i] ;
ans = max ( ans , dp[i] ) ;
}
printf ( "%.8f\n" , ans ) ;
}
int main () {
int T ;
//freopen ( "5549.in" , "r" , stdin ) ;
scanf ( "%d" , &T ) ;
for ( int i = 1 ; i <= T ; ++ i ) {
printf ( "Case #%d: " , i ) ;
solve () ;
}
return 0 ;
}
压缩后代码:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int>pii;
typedef long long LL;
#define clr(a,x) memset(a,x,sizeof a)
const int MAXN=1005;
const double eps=1e-8;
const double pi=acos(-1.0);
struct Point{
double x,y;
Point (){}
Point (double x,double y):x(x),y(y){}
Point operator - (const Point &p)const{return Point (x-p.x,y-p.y);}
Point operator + (const Point &p)const{return Point (x+p.x,y+p.y);}
Point operator * (const double &v)const{return Point (x*v,y*v);}
double operator * (const Point &p)const{return x*p.y-y*p.x;}
double cdot(Point p){return x*p.x+y*p.y;}
double len(){return sqrt(x*x+y*y);}
double angle(){return atan2(y,x);}
}s,t,p[MAXN];
int sgn(double x){return(x>eps)-(x<-eps);}
struct Segment{
Point u,v,uv;
bool operator < (const Segment&l)const{
double U1=(u-s)*uv,D1=(t-s)*uv;
double U2=(l.u-s)*l.uv,D2=(t-s)*l.uv;
double dis1=U1/D1,dis2=U2/D2;
return dis1<dis2;
}
}seg[MAXN];
struct cmp{
bool operator () (const int&a,const int&b)const{
return seg[a]<seg[b];
}
};
struct Node{
double r,d;
int idx;
Node(){}
Node(double r,int idx,int d=0):r(r),idx(idx),d(d){}
bool operator <(const Node&a)const{
if(sgn(r-a.r))return r<a.r;
if(sgn(d-a.d))return d<a.d;
return idx<a.idx;
}
}a[MAXN],b[MAXN<<1];
set<int,cmp>S;
double dis[MAXN][MAXN],dp[MAXN],val[MAXN],rl[MAXN],rr[MAXN];
int G[MAXN][MAXN],vis[MAXN],n,cnt;
int has_intersection(Point a,Point b,Point p,Point q){
int d1=sgn((b-a)*(p-a)),d2=sgn((b-a)*(q-a)),d3=sgn((q-p)*(a-p)),d4=sgn((q-p)*(b-p));
return d1*d2<0&&d3*d4<0 ;
}
bool check(){
if(S.begin()==S.end())return 1;
int o=*S.begin();
return has_intersection(s,t,seg[o].u,seg[o].v)==0;
}
void calc(int idx,int m){
sort(a,a+m);
S.clear();
int q=0;
s=p[idx];
t=s+Point (1e6,0);
for(int i=0;i<cnt;++i)if(sgn((seg[i].u-s)*(seg[i].v-s))){
vis[i]=0;
double r1=(seg[i].u-s).angle(),r2=(seg[i].v-s).angle();
if(r1>r2)swap(r1,r2);
if(has_intersection(s,t,seg[i].u,seg[i].v)==1)b[q++]=Node(r1,i),b[q++]=Node(r2,i);
else{
if(r1<0&&r2<0)continue;
if(r1<0&&r2>0)r1+=2*pi,swap(r1,r2);
b[q++]=Node(r1,i),b[q++]=Node(r2,i);
}
}
sort(b,b+q);
for(int i=0,j=0;i<m;++i){
int idi=a[i].idx;
t=p[idi];
while(j<q&&sgn(a[i].r-b[j].r)>=0){
int o=b[j++].idx;
if(!vis[o])S.insert(o);
else S.erase(o);
vis[o]^=1;
}
if(i&&sgn(a[i].r-a[i-1].r)==0)continue;
double tmpr=a[i].r;
if((sgn(rl[idx]-tmpr)<0&&sgn(tmpr-rr[idx])<0))continue;
if(tmpr<0)tmpr+=2*pi;
if((sgn(rl[idx]-tmpr)<0&&sgn(tmpr-rr[idx])<0))continue;
tmpr=a[i].r-pi;
if((sgn(rl[idi]-tmpr)<0&&sgn(tmpr-rr[idi])<0))continue;
if(tmpr<0)tmpr+=2*pi;
if((sgn(rl[idi]-tmpr)<0&&sgn(tmpr-rr[idi])<0))continue;
if(check())G[idx][idi]=G[idi][idx]=1;
}
}
void solve(){
scanf("%d",&n);
for(int i=0;i<n;++i)scanf("%lf%lf%lf",&p[i].x,&p[i].y,&val[i]);
cnt=n;
for(int i=0;i<n;++i){
int j=(i+1)%n,k=(i+2)%n;
rl[j]=(p[k]-p[j]).angle();
rr[j]=(p[i]-p[j]).angle();
if(rl[j]>rr[j])rr[j]+=2*pi;
seg[i].u=p[i];
seg[i].v=p[j];
seg[i].uv=p[j]-p[i];
}
for(int i=0;i<n;++i)for(int j=i;j<n;++j){
G[i][j]=G[j][i]=0;
dis[i][j]=dis[j][i]=(p[j]-p[i]).len();
}
for(int i=0,m;i<n;calc(i,m),++i)for(int j=m=0;j<n;++j){
if(p[j].y>p[i].y||p[j].y==p[i].y&&j>i){
a[m++]=Node((p[j]-p[i]).angle(),j,dis[i][j]);
}
}
double ans=dp[0]=val[0];
for(int i=1;i<n;++i){
dp[i]=-1e50;
for(int j=0;j<i;++j)if(G[i][j])dp[i]=max(dp[i],dp[j]-dis[i][j]);
dp[i]+=val[i];
ans=max(ans,dp[i]);
}
printf("%.8f\n",ans);
}
int main(){
int T;
scanf("%d",&T);
for(int i=1;i<=T;++i){
printf("Case #%d:",i);
solve();
}
return 0;
}