这道题是[kuangbin带你飞]专题1-23,专题五的第一道题。
题意:
有n台损坏的电脑,现要将其逐台修复,且使其相互恢复通信功能。若两台电脑能相互通信,则有两种情况,一是他们之间的距离小于d,二是他们可以借助都可到达的第三台已修复的电脑。给出所有电脑的坐标位置,对其进行两种可能的操作,O x表示修复第x台,S x y表示判断x y之间能否通信,若能输出SUCCESS,否则输出FALL。
Input:
第一行包含两个整数n和d(1<=n<=1001,0<=d<=20000)。这里n是从1到n的计算机数量,d是两台计算机可以直接通信的最大距离。在n行中,每一个包含两个整数Xi,Yi(0<=Xi,Yi=10000),这是n个计算机的坐标。从(n+1)-第行到输入端,都有一个一个地执行的操作。每行包含以下两种格式之一的操作:
1.“o p”(1<=p<=n),这意味着修复计算机p。
2.“s p q“(1<=p,q<=n),这意味着测试计算机p和q是否可以通信。
输入不超过300000行。
Output:
对于每个测试操作,如果两台计算机可以通信,则打印“成功”,否则打印“失败”。
思路
先建一个图,表示电脑都是好的时候能相互通信的网络。
对于维修操作,将被维修的电脑和与其相连的且为好的电脑合并到一个并查集中。
对于查询操作,判断两者是否在一个集合中即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
struct node{
double x;
double y;//记录电脑的坐标
}arr[1005];
int pre[1005],flag[1005];
char op[2];
double dis(node a,node b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));//计算两台电脑的距离
}
int n,d,x,y,num;
void init(){
num=0;
memset(flag,0,sizeof(flag));
for(int i=1;i<1005;i++)
pre[i]=i;//一开始祖先都赋值为自己
}
int find(int x){
if(x==pre[x])
return x;
else return pre[x]=find(pre[x]);//并查集查找祖先函数
}
void merge(int x,int y){//并查集合并函数
int fx=find(x);
int fy=find(y);
if(fx!=fy) pre[fx]=fy;
}
int main(){
init();
scanf("%d %d",&n,&d);
for(int i=1;i<=n;i++){
scanf("%lf %lf",&arr[i].x,&arr[i].y);//先读入n台电脑的坐标
}
while(~scanf("%s",op)){//不确定有几个操作
if(op[0]=='O'){
scanf("%d",&x);
for(int i=0;i<num;i++){
if(dis(arr[flag[i]],arr[x])<=d)//需要每次都判断修好的x号与其他修好的能否通信
merge(flag[i],x);
}
flag[num++]=x;//flag数组里面存的是修好的电脑的序号
}
else if(op[0]=='S'){
scanf("%d %d",&x,&y);
if(find(x)==find(y))
printf("SUCCESS\n");
else printf("FAIL\n");
}
}
return 0;
}