题目大意:现有n台需要修复的电脑(编号1~N),某两台电脑之间是否能通信的标准有两个。第一:两台电脑相距的距离小于d;第二,两台电脑可以通过其他电脑通信。
输入信息:首先会给出电脑的数量N和额定距离d,然后会给出各台电脑的坐标xi和yi。然后会给出对电脑的两种操作,分别是修复和查询。修复命令为O i,表示修复第i台电脑;查询操作为S i j,表示查询第i台电脑和第j台电脑之间是否能够通信。
输出信息:再输入查询命令时需要输出“SUCCESS”或者“FAIL”来回答这两台电脑是否能够通信。
思路:首先,这里有个隐含的条件,如果两台电脑可以通信,这两台电脑必须是已经被修复了的。其次,如果某些电脑之间可以互相通信,则可以将他们看作一个集合。查询某两台电脑是否属于一个集合的问题合一用并查集很好的解决。步骤为:1,修复某台电脑时,依次检查其他各台电脑,将小于额定距离且已经被修复的电脑加入同一集合。2,查询某两台电脑是否能够通信时,直接检查这两台电脑是否属于同一集合,若属于同一集合,则能够通信;若不属于,则不能通信。
#include <stdio.h>
#include <iostream>
#include <math.h>
using namespace std;
typedef pair<int, int> P;
int par[20000],rank[20000];
int N,D;
P point[1001]; //各电脑坐标
int state[1001]; //各电脑修复状态,已修复为1,未修复为0
void init(int n)
{
for(int i = 0; i < n; i++)
{
par[i]=i;
rank[i]=0;
}
}
int find(int x)
{
if(par[x] == x)
return x;
else
return par[x]=find(par[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x == y)
return;
if(rank[x] < rank [y])
par[x] = y;
else
{
par[y] = x;
if(rank[x] == rank[y])
rank[x]++;
}
}
bool same(int x,int y)
{
return find(x) == find(y);
}
//检查某两台电脑之间的距离是否符合要求,若符合则返回1;若不符合返回0
int dis(int m_i , int m_j)
{
int ret, delta_x, delta_y;
delta_x = pow(point[m_i].first - point[m_j].first, 2);
delta_y = pow(point[m_i].second - point[m_j].second, 2);
if(delta_x + delta_y <= D*D)
return 1;
else return 0;
}
int main()
{
cin >> N >> D;
init(N);
int tmp_i, tmp_j;
P tmp_p;
for(int i = 1; i <= N; i++) //保存各电脑坐标
{
cin >> tmp_i >> tmp_j;
tmp_p = make_pair(tmp_i, tmp_j);
point[i] = tmp_p;
}
char opera;
int num_1, num_2;
while(cin >> opera)
{
if(opera == 'O')
{
cin >> num_1;
state[num_1] = 1;
for(int i = 1; i <= N; i++) //依次检查其他各台电脑,将小于额定距离且已经被修复的电脑加入同一集合
{
if(i == num_1)
continue;
if(state[i] && state[num_1] && !same(i, num_1) && dis(i, num_1))
unite(i, num_1);
}
}
else if(opera == 'S') //检查这两台电脑是否属于同一集合,若属于同一集合,则能够通信;若不属于,则不能通信
{
cin >> num_1 >> num_2;
if(same(num_1, num_2))
cout<< "SUCCESS" << endl;
else cout<< "FAIL" << endl;
}
}
return 0;
}