【HDU】5549 Walk Around The Campsite【极角排序+set+最短路dp】

题目链接:Walk Around The Campsite

题目大意:给一个简单多边形,每次只能从多边形上编号 i 的点到编号j的点,其中 i<j ,且 i j只能走直线,并且路线上不能经过任何其他的多边形顶点,且不能走到多边形内。
题目分析:要知道多边形的边只会在端点相交。则如果以一个点为原点,作射线,然后旋转,那么遇到边的左端点我们往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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值