【GDOI2015模拟12.20】鸡腿の梦境

Description:

鸡腿做了一个好梦呢!他化身钢铁侠大战全宇宙的各种怪物,并且取得了胜利。在梦的结尾,鸡腿开的飞船困在了一片废弃飞船群中,同时由于引擎故障,他只能在平面内移动。废弃飞船群可以描述为许多圆形的飞船,当然因为各种奇怪的原因,飞船可能叠加在一切。鸡腿也驾驶着飞船在这个平面中。一开始的时候鸡腿的飞船是不会和废弃的飞船有叠加部分的,鸡腿驶出这片区域时,可以蹭过某一个废弃飞船,但不能撞上更不能挤开它(质量问题),更不能和废弃飞船叠起来。鸡腿要立刻离开这片区域进行补给,你能告诉他现有条件下可以离开这片废弃飞船群吗?

N ≤ 300,数据组数 ≤ 5。

题解:

显然先把飞船的圆转移到障碍物的圆上,那么就变成了一个点是否能逃出生天。

如果两个圆相交,连边。

很容易想到的一种做法是判断点是否在一个环构成的多边形里。

*n元环没有多项式算法。

考虑换个思路,从这个点随机射一条射线,与它相交的边的权值为1。

现在要找一个权值和为奇数的环,这个显然就很简单了,BFS一就好了。

Code:

#include<cmath>
#include<cstdio>
#define db long double
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;

const int N = 305;
const db eps = 1e-10;
const db theta = 0.5;

struct P {
    db x, y;
    P(db _x = 0, db _y = 0) {x = _x, y = _y;}
} a[N], b;

P angle(db x) {return P(cos(x), sin(x));}
P operator *(P a, P b) {return P(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);}
P rotate(P a, db b) {return a * angle(b);}
db dis(P a, P b) {return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));}

int n; db x, y, xx, yy, R, r[N];

int ans, bz[N][N], f[N][2], d[N * N * 2][2], d0;

int main() {
    while(scanf("%d", &n) != EOF) {
        fo(i, 1, n) scanf("%Lf %Lf %Lf", &a[i].x, &a[i].y, &r[i]);
        scanf("%Lf %Lf %Lf", &x, &y, &R);
        fo(i, 1, n) r[i] += R;
        fo(i, 1, n) a[i] = rotate(a[i], theta);
        b = rotate(P(x, y), theta); x = b.x; y = b.y;
        b = rotate(P(3838, 4444), theta);
        db k1 = (b.y - y) / (b.x - x), b1 = y - k1 * x;
        fo(i, 1, n) fo(j, 1, n) bz[i][j] = 0;
        fo(i, 1, n) fo(j, i + 1, n)
            if(dis(a[i], a[j]) + eps < r[i] + r[j]) {
                bz[i][j] = bz[j][i] = 1;
                int k2 = (a[j].y - a[i].y) / (a[j].x - a[i].x), b2 = a[j].y - a[j].x * k2;
                xx = (b2 - b1) / (k1 - k2); yy = xx * k1 + b1;
                if(xx + eps > x && xx + eps > min(a[i].x, a[j].x) && xx - eps < max(a[i].x, a[j].x))
                    bz[i][j] = bz[j][i] = 2;
            }
        fo(i, 1, n) f[i][0] = f[i][1] = 0; ans = 1;
        fo(i, 1, n) if(!f[i][0] && !f[i][1]) {
            d[d0 = 1][0] = i; d[1][1] = 0;
            fo(j, 1, d0) {
                int u = d[j][0], v = d[j][1];
                fo(j, 1, n) if(bz[u][j]) {
                    int nv = v ^ (bz[u][j] > 1);
                    if(!f[j][nv]) f[j][nv] = 1, d[++ d0][0] = j, d[d0][1] = nv;
                }
            }
            if(f[i][1]) {
                ans = 0; break;
            }
        }
        if(ans) printf("YES\n"); else printf("NO\n");
    }
}

猜你喜欢

转载自blog.csdn.net/cold_chair/article/details/80992333