【ACdream】1215 Get Out! 负环判断

传送门:【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 ;
}


你可能感兴趣的:(HDU)