1. 程式人生 > >計蒜客 奶酪 (並查集)

計蒜客 奶酪 (並查集)

long con print 知識 sca clas 之間 mark author


鏈接 : Here!

思路 :

  • 其實這個是一道簡單的並查集問題, 判斷$Jerry$是否能從下表面跑到上表面, 其實質上是判斷上表面和下表面是否連通, 因此這道問題就變成了判斷連通性的問題了. 判斷標準是如果$d <= 2 * r$ ($d$為兩球心之間的距離), 那麽就合並兩個集合即可

思考 : 將知識穿成線索,做等價遷移,將復雜問題變成簡單問題.

代碼 :

/*************************************************************************
    > File Name: t13.cpp
    > Author: 
> Mail: > Created Time: 2017年11月21日 星期二 16時33分31秒 ************************************************************************/ #include <cstdio> #include <algorithm> #include <cstdlib> #include <cstring> #include <cmath> using namespace std; #define MAX_N 1010
typedef long long ll; int par[MAX_N]; int size[MAX_N]; ll n, h, r; struct Point { ll x, y, z; }; double check(Point a, Point b) { return (sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z)) <= 2 * r); } void init() { for (int i = 0 ; i < MAX_N ; ++i) { par[i] = i; size[i] = 1
; } } int find(int x) { return x == par[x] ? x : (par[x] = find(par[x])); } void merge(int x, int y) { x = find(x); y = find(y); if (x == y) return; if (size[x] > size[y]) { size[x] += size[y]; par[y] = x; } else { size[y] += size[x]; par[x] = y; } } int same(int x, int y) { return find(x) == find(y); } int main() { int T; scanf("%d", &T); while (T--) { init(); Point data[MAX_N]; scanf("%lld%lld%lld", &n, &h, &r); for (int i = 2 ; i <= n + 1 ; ++i) { scanf("%lld%lld%lld", &data[i].x, &data[i].y, &data[i].z); } // 先把能接觸到地面的點加入到地面集合0中 for (int i = 2 ; i <= n + 1 ; ++i) { if (fabs(0 - data[i].z) > r) continue; if (same(0, i)) continue; merge(0, i); } // 再把能接觸到上端的點加入到頂端集合1中 for (int i = 2 ; i <= n + 1 ; ++i) { if (fabs(h - data[i].z) > r) continue; if (same(1, i)) continue; merge(1, i); } for (int i = 2 ; i <= n + 1 ; ++i) { for (int j = 2 ; j <= n + 1 ; ++j) { if (same(i, j)) continue; if (!check(data[i], data[j])) continue; merge(i, j); } } if (same(0, 1)) { printf("Yes\n"); } else { printf("No\n"); } } return 0; }

計蒜客 奶酪 (並查集)