算法分析和复杂性理论 / 22年算法课上机题目合集AC:Wireless Network【POJ-2236】

题目 Wireless Network

描述

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.

输入

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.

输出

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

样例输入

4 1

0 1

0 2

0 3

0 4

O 1

O 2

O 4

S 1 4

O 3

S 1 4

样例输出

FAIL

SUCCESS

思路分析

    题目:无向图结构,每个节点具有x,y坐标,用于计算距离,坐标初始不可用并依次恢复为可用。要求对指定的两个节点,判断是否存在一条路径,路径节点全部可用且相邻节点的距离不大于d。

    输入:节点数N和判断距离d为整数(1 <= N <= 1001, 0 <= d <= 20000);节点序号从1开始计数,分别为1-N;首先给出N和d两个数据,接着给出N×2个数据分别代表N个节点的x、y坐标(0 <= xi, yi <= 10000),接着输入两种指令,O p代表p节点恢复可用,S p q代表判断p、q节点是否存在路径并要求输出结果”SUCCESS”或”FAIL”。

    解决方案:两节点直接距离的判断可以用(x1-y1)²+(x2-y2)²和d²比较,当节点A、B的直接距离≤d时,如果C、A的直接距离≤d,则C也与B连通(通过路径C->A->B)。因此可以将A、B看做一个集合,当外部节点与集合中某个点的直接距离≤d,则该节点与集合中所有节点均连通。对集合A、B和集合C、D,若A与C的直接距离≤d,则A、B、C、D可以合并为一个集合,彼此连通。集合、合并集合、判断是否属于同一集合,因此想到并查集的解决方案。

    算法细节:需要创建如下变量①int n用于保存节点数②long long d保存距离d③int arr[1005]用于保存并查集leader信息,初始化为全-1④int n用于保存节点数⑤long long dx[1005], dy[1005]保存节点坐标⑥int rep[1005]表示节点是否可用,初始化为全0⑦char ch[10]读取指令类型

    初始化arr、rep、dx、dy数组,while循环接收指令,当指令为O p时,令rep[p]为1表示节点p可用,遍历节点O(n),当遍历的节点i可用且节点p距离≤d时合并节点Union(arr,i,p);当指令为O p q时,查询p q的leader并比较是否相同输出结果

过程中的错误 

几次错误都可以避免,一定要先在本地确保测试案例无误再提交代码。

①小于等于d看成了小于d;

②忘记初始化数组rep为全0;

③利用int通过后,发现20000的范围不是很拿得准,改成long long后忘记改函数传参指针;

    C++中int取值范围:10^9,-2147483648 ~ 2147483647

    C++中long long取值范围:10^18,-9223372036854775808 ~ 9223372036854775807

AC代码

#include<iostream>
using namespace std;

void Initial(int* arr, int n) {
    for (int i = 1; i <= n; i++) arr[i] = -1;
}

int Find(int* arr, int x) {
    int root = x;
    while (arr[root] >= 0) {
        root = arr[root];
    }
    while (x != root) {
        int t = arr[x];
        arr[x] = root;
        x = t;
    }
    return root;
}

void Union(int* arr, int x, int y) {
    int root1 = Find(arr, x);
    int root2 = Find(arr, y);
    if (root1 != root2) {
        if (root1 < root2) {
            arr[root1] += arr[root2];
            arr[root2] = root1;
        }
        else {
            arr[root2] += arr[root1];
            arr[root1] = root2;
        }
    }
}

bool dis(long long* dx, long long* dy, long long d, int i, int p) {
    if ((dx[i] - dx[p]) * (dx[i] - dx[p]) + (dy[i] - dy[p]) * (dy[i] - dy[p]) <= d * d) {
        return true;
    }
    else {
        return false;
    }
}

int main() {
    ios::sync_with_stdio(false);

    int n;
    long long d;
    int arr[1005], rep[1005];
    long long dx[1005], dy[1005];
    char ch[10];
    int p, q;

    cin >> n >> d;
    Initial(arr, n);
    for (int i = 1; i <= n; i++) {
        rep[i] = 0;
    }

    for (int i = 1; i <= n; i++) {
        cin >> dx[i] >> dy[i];
    }

    while (cin >> ch) {
        if (ch[0] == 'O') {
            cin >> p;
            rep[p] = 1;
            for (int i = 1; i <= n; i++) {
                if (rep[i] && dis(dx, dy, d, i, p)) {
                    Union(arr, i, p);
                }
            }
        }
        else {
            cin >> p >> q;
            if (Find(arr, p) == Find(arr, q) && rep[p] && rep[q]) {
                cout << "SUCCESS" << endl;
            }
            else {
                cout << "FAIL" << endl;
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值