Wireless Network (POJ - 2236)

版权声明:转载请注明 https://blog.csdn.net/li13168690086/article/details/81347581

题目描述

  An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computers, but an unexpected aftershock attacked, all computers in the network were all broken. The computers are repaired one by one, and the network gradually began to work again. Because of the hardware restricts, each computer can only directly communicate with the computers that are not farther than d meters from it. But every computer can be regarded as the intermediary of the communication between two other computers, that is to say computer A and computer B can communicate if computer A and computer B can communicate directly or there is a computer C that can communicate with both A and B. 
In the process of repairing the network, workers can take two kinds of operations at every moment, repairing a computer, or testing if two computers can communicate. Your job is to answer all the testing operations. 

  Input

  The first line contains two integers N and d (1 <= N <= 1001, 0 <= d <= 20000). Here N is the number of computers, which are numbered from 1 to N, and D is the maximum distance two computers can communicate directly. In the next N lines, each contains two integers xi, yi (0 <= xi, yi <= 10000), which is the coordinate of N computers. From the (N+1)-th line to the end of input, there are operations, which are carried out one by one. Each line contains an operation in one of following two formats: 
1. "O p" (1 <= p <= N), which means repairing computer p. 
2. "S p q" (1 <= p, q <= N), which means testing whether computer p and q can communicate. 
  The input will not exceed 300000 lines. 

Output

  For each Testing operation, print "SUCCESS" if the two computers can communicate, or "FAIL" if not.

Sample Input

4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4

Sample Output

FAIL
SUCCESS

题目分析

  所要解决的问题是修复电脑 ,在一场地震后,有N台电脑损坏,需要逐个修复。修复后的电脑,能够连接距离自身D米以内的其他电脑,并且具有传递性(2连1,2连3,那么1也可以连3)。看一眼输入:首先第一行,我们会得到损坏电脑的数量N,和连接距离D;接下来N行,我们会得到每台电脑的坐标X,Y(用于计算距离);最后会读入不超过300000行的动作命令。关于命令,是这样描述的:有两种命令,每种命令带一个标记。命令1是"O",后面会跟一个数字p,所代表的意思是修复第p台电脑;命令2是"S",后面跟两个数字p和q,表示测试连接第p和第q台电脑,如果可以连接,那么需要输出"SUCCESS",否则输出"FAIL"。

  因此我们的输出,关注命令2,遇到了,就要准备输出。那么如何判断p与q的是否连通,就是问题的关键。

解题思路

  如果电脑2和1被修复了,且相隔距离在D以内,那么就视作连通;若此时电脑2和电脑3也可以连通,自然电脑1和电脑3同样被视作连通。这样就相当于,可以互相连通的电脑组成了一个集合。只要判定测试的两台电脑,此时,是否在同一个集合里,那就可以知道是否连通。这符合并查集的思想,所以用并查集的数据结构存储,可以相互连通的电脑,再寻找p和q的根源结点,看是否相同,就可判定如何输出了。

  其次关注如何存储连通的电脑。首先存入所有电脑坐标,然后每当获取了O命令(修复命令),就遍历已修复点内,是否有可连接的电脑(通过距离判断),如果存在就双双合并为同一个集合,直到遍历完毕。

(*注:对于并查集的理解,请参照并查集初步理解。)

AC代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int MAX_N (10100);
int par[MAX_N];
int ran[MAX_N];

void init(int n){
    for(int i = 1; i <= n; i++){
        par[i] = i;
        ran[i] = 0;
    }
}

int find (int x)  //用迭代寻找
{
    int root = x;
    while (root != par[root])
    {
        root = par[root];
    } //找到根结点
    int y;
    while (x != root) {  //压缩路径,从点X开始往上找值,并将其赋值为根结点的值。
        y = par[x];
        par[x] = root;
        x = y;
    }
    return root;
}

void unite(int x, int y){
    x = find(x);
    y = find(y);
    if(x == y)
        return;
    if(ran[x] < ran[y])
        par[x] = y;
    else{
        par[y] = x;
        if(ran[x] == ran[y])
            ran[x]++;
    }
    return;
}

bool same(int x, int y){
    return find(x) == find(y);
}

struct Cor{     //构造坐标结构体
    double x,y;
};

double dis(Cor a,Cor b){    //距离计算函数
    return pow(pow(a.x-b.x,2)+pow(a.y-b.y,2),0.5);;
}

int main() {
    int n,d;
    scanf("%d %d",&n,&d);
    Cor coor[n+1];  //建立电脑位置数组
    init(n);        //重要的初始化
    for(int i = 1; i <= n; i++)
        scanf("%lf %lf",&coor[i].x,&coor[i].y);
    int rap[n+1],j=0;   //新建一个修复数组,用于存储已修复的电脑编号。
    memset(rap, 0, sizeof(rap));
    char a;
    int b,c;
    while(cin >> a){
        if(a == 'O'){      //如果为"O"命令
            scanf("%d",&rap[j]);    //读入修复编号
            for(int i = 0; i < j; i++){     //不断遍历,一旦距离符合,就合并
                double k = dis(coor[rap[i]], coor[rap[j]]); //计算距离
                if(k <= d)
                    unite(rap[i],rap[j]);   //合并
            }
            j++;    //修复数组编号加1
        }
        else if(a == 'S'){      //"S"命令
            cin >> b >> c;      //读入测试的两个电脑编号
            if(same(b,c) == 1)  //如果根源结点是否一致
                cout << "SUCCESS" << endl;
            else
                cout << "FAIL" << endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/li13168690086/article/details/81347581
今日推荐