思路:初始时各个节点与自己都不连通,所以pre值为-1,每进行一次O操作,就先把点A的pre值设为自己,然后遍历在d范围内的所有点把它们联通。
坑点:
1、注意O是字母O,而不是0
2、因为初始值为-1,所以假如查询一个没有进行过O操作的点时,不加特判会死循环
#include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <cstdio> using namespace std; const int N = 1010; int pre[N]; struct Point{ double x, y; }; double cal_dis(Point p1, Point p2){ return (sqrt((p1. x - p2. x) * (p1. x - p2. x) + (p1. y - p2. y) * (p1. y - p2. y))); } int find(int x){ int r = x; while(pre[r] != r){ if(pre[r] == -1) return -1; r = pre[r]; } int i = x, j; while(i != r){ j = pre[i]; pre[i] = r; i = j; } return r; } void join(int x, int y){ int t1 = find(x), t2 = find(y); if(t1 != t2){ pre[t2] = t1; } } int main(){ int n, d; scanf("%d%d", &n, &d); Point p[N]; for(int i = 1; i <= n; i ++){ scanf("%lf%lf", &p[i]. x, &p[i]. y); } memset(pre, -1, sizeof(pre)); char c; while(cin >> c){ int a, b; if(c == 'O'){ scanf("%d", &a); pre[a] = a; for(int i = 1; i <= n; i ++){ if(pre[i] != -1){ if(cal_dis(p[a], p[i]) <= d){ join(a, i); } } } } else{ scanf("%d%d", &a, &b); int x1 = find(a), x2 = find(b); if(x1 == -1 || x2 == -1) cout << "FAIL" << endl; else{ if(find(a) == find(b)) cout << "SUCCESS" << endl; else cout << "FAIL" << endl; } } } return 0; }ps:这东西比最短路简单多了,那几个算法的证明简直恐怖(꒪Д꒪)ノ