传送门:【ACdream】1215 Get Out!
题目分析:首先将所有点平移,使得人在原点位置。然后所有圆的半径加上人的半径(人变成了点),然后对每两个圆之间判断,如果这两个圆有两个交点,则对这两个圆建边。那么题目就转化成了判断人是否在多边形内。如果我们将每条边变成两条有向边,边的权值为有向弧度。那么如果点在多边形内,则必定存在多边形边权和等于2pi或-2pi,也就是说存在负环。如果点不在多边形内,则该多边形权值和等于0。那么我们只要用spfa判断是否存在负环即可。
注意精度问题= =。。因为这个导致我一开始一直TLE。。
代码如下:
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std ; #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 305 ; const int MAXE = 100005 ; const double INF = 1e15 ; const double eps = 1e-8 ; const double pi = acos ( -1.0 ) ; struct Edge { int v , n ; double c ; Edge () {} Edge ( int v , double c , int n ) : v ( v ) , c ( c ) , n ( n ) {} } ; 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 ) ; } } ; struct Circle { Point p ; double r ; void input () { scanf ( "%lf%lf%lf" , &p.x , &p.y , &r ) ; } } ; Edge E[MAXE] ; Circle C[MAXN] ; int H[MAXN] , cntE ; double d[MAXN] ; int vis[MAXN] , Time ; int Q[MAXN] , head , tail ; int use[MAXN] ; int n ; void clear () { cntE = 0 ; clr ( use , 0 ) ; clr ( H , -1 ) ; } void addedge ( int u , int v , double c ) { E[cntE] = Edge ( v , c , H[u] ) ; H[u] = cntE ++ ; } double dist ( const Point& p ) { return sqrt ( p.x * p.x + p.y * p.y ) ; } int dcmp ( double x ) { return ( x > eps ) - ( x < -eps ) ; } int spfa ( int s ) { For ( i , 1 , n ) d[i] = INF ; //clr ( use , 0 ) ; ++ Time ; head = tail = 0 ; Q[tail ++] = s ; d[s] = 0 ; use[s] = 1 ; while ( head != tail ) { int u = Q[head ++] ; if ( head == MAXN ) head = 0 ; vis[u] = Time - 1 ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( dcmp ( d[v] - d[u] - E[i].c ) > 0 ) { d[v] = d[u] + E[i].c ; if ( Time != vis[v] ) { vis[v] = Time ; use[v] ++ ; if ( use[v] == n + 5 ) return 1 ; Q[tail ++] = v ; if ( tail == MAXN ) tail = 0 ; } } } } return 0 ; } void solve () { Circle a ; clear () ; For ( i , 1 , n ) C[i].input () ; a.input () ; For ( i , 1 , n ) { C[i].p = C[i].p - a.p ; C[i].r += a.r ; } For ( i , 1 , n ) { For ( j , i + 1 , n ) { if ( dcmp ( dist ( C[i].p - C[j].p ) - ( C[i].r + C[j].r ) ) < 0 ) { double ang1 = atan2 ( C[i].p.y , C[i].p.x ) ; double ang2 = atan2 ( C[j].p.y , C[j].p.x ) ; if ( dcmp ( ang1 ) < 0 ) ang1 = 2 * pi + ang1 ; if ( dcmp ( ang2 ) < 0 ) ang2 = 2 * pi + ang2 ; double ang = ang1 - ang2 ; if ( dcmp ( ang - pi ) > 0 ) ang = ang - 2 * pi ; if ( dcmp ( ang + pi ) < 0 ) ang = 2 * pi + ang ; addedge ( i , j , ang ) ; addedge ( j , i , -ang ) ; } } } For ( i , 1 , n ) if ( spfa ( i ) ) { printf ( "NO\n" ) ; return ; } printf ( "YES\n" ) ; } int main () { clr ( vis , 0 ) ; Time = 0 ; while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }