[并查集]无线网络

版权声明:本文章由一枚蒟蒻提供 https://blog.csdn.net/SSL_QYH0Ice/article/details/79182545

题目描述
有一个由n台计算机组成的无线网络。(n <= 1001),正常情况下,每台计算机都能跟与它距离不超过d的任何计算机通讯(d <= 20000)。地震发生了。所有的计算机都陷入瘫痪。专家们试着一台一台地修复计算机,以恢复整个无线网络。有时在修复的过程中,他们需要测试一下某两台计算机能否通讯(如果他们能通过别的正常的计算机进行通讯,也算他们之间可以通讯,即“能否通讯”可以是间接的)。
你的任务,就是模拟修复网络的过程,并回答“能否通讯”的询问。

Input

第一行两个整数,N和d,N表示计算机的数目,d表示两台计算机直接可直接通讯的最大距离。接下来的N行,每行两个整数Xi,Yi,表示每台计算机的坐标。接下来有许多行,每行都是一个操作(或者是修复操作,或者是询问操作)。
操作的格式如下:
O p (1 <= p <= N) 修复操作,表示修复编号为p的电脑;
S p q (1 <= p, q <= N) 询问操作,询问编号为p和编号为q的电脑能否通讯。
如果一台电脑尚未被修复,则它不能和任何电脑通讯。

Output

对于每个询问操作:如果能够通讯,输出一行SUCCESS;如果无法通讯,输出一行FAIL

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

对于100%的数据,N <= 1001, 操作次数 <= 300000。

分析
首先这题让我们求两个点之间的关系,很容易想到并查集
我们预处理一下,用邻接矩阵把一个点半径内能连接的电脑全部连边,用布尔数组判断点是否被激活
然后合并时要判断是否被连边和连接点是否被激活
还有重点:

明明并查集合并时已经判断过要连接的点是否被激活了,输出时仍然需要判断两点是否被激活!

它有可能询问同一台电脑是否能与同一台电脑通讯,但是题目说过:没有激活,无法通讯连自己都不能通讯也是牛逼了

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int n,d;
int f[1002];
bool q[1002],map[1002][1002];
char c;
int getf(int a)
{
    if (f[a]==a) return a;
    int root=getf(f[a]);
    f[a]=root;
    return root;
}
void merge(int a,int b)
{
    int i=getf(a),j=getf(b);
    f[i]=j;
}
void init()
{
    int i,j,k=0;
    int x[1001],y[1001];
    scanf("%d%d\n",&n,&d);
    for (i=1;i<=n;i++)
    {
        scanf("%d%d\n",&x[i],&y[i]);
        f[i]=i;
    }
    for (i=1;i<=n;i++)
    for (j=1;j<=n;j++)
    if (i!=j)
    if ((double)sqrt(pow(x[i]-x[j],2)+pow(y[i]-y[j],2))<=(double)d)
    map[i][j]=1;
}
void doit()
{
    int i,a,b,k;
    while (scanf("%c",&c)!=EOF)
    {
        if (c=='O')
        {
            scanf("%d\n",&a);
            q[a]=1;
            for (k=1;k<=n;k++)
            if (q[k]&&map[a][k])
            merge(a,k);
        }
        if (c=='S')
        {
            scanf("%d%d\n",&a,&b);
            if (q[a]&&q[b]&&getf(a)==getf(b)) printf("SUCCESS\n");
            else printf("FAIL\n");
        }
    }
}
int main()
{
    init();
    doit();
}
阅读更多
换一批

没有更多推荐了,返回首页