B

题意:在一个平面中,有n台电脑,但是此时所有的电脑都是坏的,给出每台电脑的坐标(x,y)和一个距离d
如果电脑是好的,并且电脑之间的距离小于d,那么这两台电脑就可以联通,电脑可以借助电脑联通,也就是说,如果
a--b   b--c  那么可以认为 a--c  。现在给出两种操作, ‘O’ 表示修理某一台电脑,‘S’表示查询 两台电脑是否联通
是 则输出“SUCCESS” 否则输出“FAIL”
 
思路: 很明显的一个并查集题目,如果两台电脑之间的距离小于d,就认为他们直接有联系,如果两台电脑都是修好的,并且有联系,就认为他们可以联通,把这两台电脑合并集合。查询就直接判断两台电脑是否在一个集合中即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int n,D;
int par[1005],rk[1005],link[1005][1005],vis[1005]//link记录联系,vis记录是否被修好;
int X[1005],Y[1005];//记录坐标
void init()//初始化
{
    for(int i=1;i<=n;i++){
        par[i]=i;
        rk[i]=0;
    }
}
int Find(int x)//查找(最好写成非递归的查找方式)
{
    while(x!=par[x])
       x=par[x];
    return x;
}
void unite(int x,int y)//合并
{
    x=Find(x);
    y=Find(y);
    if(x==y)
        return ;
    if(rk[x]<rk[y])
        par[x]=y;
    else{
        par[y]=x;
        if(rk[x]==rk[y])
            rk[x]++;
    }
}
bool same(int x,int y)//判断是否处于一个集合
{
    return Find(x)==Find(y);
}
int main()
{
    memset(link,0,sizeof link);
    memset(vis,0,sizeof vis);
    scanf("%d%d",&n,&D);
    init();
    for(int i=1;i<=n;i++)
        scanf("%d%d",&X[i],&Y[i]);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++){
        if((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j])<=D*D){//建立联系
            link[i][j]=1;
        }
    }
    char ch[2];
    int a,b;
    while(~scanf("%s",ch)){
        if(ch[0]=='O'){//修好一台电脑,就判断此台电脑是否可以和其他电脑联通
            scanf("%d",&a);
            vis[a]=1;
            for(int i=1;i<=n;i++)
                if(vis[i]==true&&i!=a&&link[a][i])
                    unite(a,i) ;
            }
        else if(ch[0]=='S'){
            scanf("%d%d",&a,&b);
            if(same(a,b))
                printf("SUCCESS
");
            else
                printf("FAIL
");
        }
    }
    return 0;
}
View Code

原文地址:https://www.cnblogs.com/Levi-0514/p/9042487.html