NOIP 2017 奶酪 (BFS)

Description

现有一块大奶酪,它的高度为 hh,它的长度和宽度我们可以认为是无限大的,奶酪 中间有许多 半径相同 的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中, 奶酪的下表面为z = 0z=0,奶酪的上表面为z = hz=h。
现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐 标。如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别 地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞;如果 一个空洞与上表面相切或是相交,Jerry 则可以从空洞跑到奶酪上表面。
位于奶酪下表面的 Jerry 想知道,在 不破坏奶酪 的情况下,能否利用已有的空洞跑 到奶酪的上表面去?

Solution

可以相连的空洞间连边,BFS判断相通即可。

Code

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>

using namespace std;

typedef long long LL;
#define For(i, j, k) for (int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))

template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }

const int maxn = 1003, maxm = 1000003;

struct DCR
{
    LL x, y, z;
    bool operator < (const DCR &dcr) const { return z < dcr.z; }
}a[maxn];

LL r, h;
int n, beg[maxn], nex[maxm], v[maxm], e, T;
bool vis[maxn], isend[maxn];
queue<int> q;

inline void add(int uu, int vv) { v[++ e] = vv; nex[e] = beg[uu]; beg[uu] = e; }

LL dist(DCR A, DCR B) { return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z); }

inline void Init()
{
    cin >>n >> h >> r;
//  scanf("%d%lld%lld", &n, &h, &r);
    For(i, 1, n) cin >>a[i].x >>a[i].y >> a[i].z;//scanf("%lld%lld%lld\n", &a[i].x, &a[i].y, &a[i].z);
    sort(a + 1, a + 1 + n);
    e = 0; Set(beg, 0);
    For(i, 1, n - 1)
        For(j, i + 1, n)
        {
            if (a[j].z - a[i].z > 2 * r) break;
            if (dist(a[i], a[j]) <= 4 * r * r) add(i, j), add(j, i);
        }
}

inline bool BFS()
{
    Set(vis, 0); Set(isend, 0);
    while (!q.empty()) q.pop();
    For(i, 1, n) if (a[i].z <= r) { q.push(i); vis[i] = 1; if (h-a[i].z <=r) return 1; } else break;
    Fordown(i, n, 1) if (h - a[i].z <= r) isend[i] = 1; else break;
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        for (int i = beg[u]; i; i = nex[i]) if (!vis[v[i]])
        {
            vis[v[i]] = 1;
            if (isend[v[i]]) return 1;
            q.push(v[i]);
        }
    }
    return 0;
}

int main()
{
    scanf("%d", &T);
    while (T --) {
        Init();
        if (BFS()) puts("Yes"); else puts("No");
    }
    return 0;
}
//云开远见汉阳城,犹是孤帆一日程。
//估客昼眠知浪静,舟人夜语觉潮生。
//三湘愁鬓逢秋色,万里归心对月明。
//旧业已随征战尽,更堪江上鼓鼙声。
//--卢纶《晚次鄂州》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值