解题思路:
并查集的简单应用,对每次修好的电脑对其它已经修好的电脑遍历,
如果距离小于等于最大通信距离就将他们合并。之后判断2台电脑是不是一个集合中就KO了
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.
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.
4 1 0 1 0 2 0 3 0 4 O 1 O 2 O 4 S 1 4 O 3 S 1 4Sample Output
FAIL
SUCCESS
这道题WA了好几发,后来发现思路错了,重新写了下:
#include<iostream>
#include<cstring>
#include<cmath>
int n,a,b,d;
char s;
int map[1002][2],father[1002];
bool dis[1002][1002],work[1002];
void init()
{
for(int i=1;i<=n;i++)
father[i]=i;
}
int cal(int x1,int y1,int x2,int y2)
{
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
int find_father(int i)
{
if(father[i]==i)
return i;
else
father[i]=find_father(father[i]);
return father[i];
}
void merge(int i,int j)
{
int t1,t2;
t1=find_father(i);
t2=find_father(j);
if(t1!=t2)
{
father[t2]=t1;
}
return ;
}
int main()
{
using namespace std;
int i,j;
while(cin>>n>>d)
{
memset(work,false,sizeof(work));//初始化为全部不能工作
init();
for(i=1;i<=n;++i)
cin>>map[i][0]>>map[i][1];//输入computer的座标
for(i=1;i<=n;++i)
for(j=1;j<=i;++j)
{
//判断是否两台computer的距离是否小于d
int t=cal(map[i][0],map[i][1],map[j][0],map[j][1]);
if(t<=d*d)
dis[i][j]=dis[j][i]=true;
else
dis[i][j]=dis[j][i]=false;
}
while(cin>>s)
{
if(s=='O')
{
cin>>a;
work[a]=true;
for(i=1;i<=n;++i)
{
if(i!=a&&work[i]&&dis[i][a])
merge(i,a);
}
}
else if(s=='S')
{
cin>>a>>b;
if(find_father(a)==find_father(b))
cout<<"SUCCESS"<<endl;
else
cout<<"FAIL"<<endl;
}
}
}
return 0;
}
然后后看了一下别人写的代码(很不争气的看了LOL),发现了有趣的东西:
#include<iostream>
#include<cstring>
#include<cmath>
int point[1002][2],root[1002];
bool dis[1002][1002],work[1002];
int cal(int x1,int y1,int x2,int y2)
{
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
int find_root(int i)//刚开始发现了,这里和我自己写的不一样,天真的改成自己写的,结果WA了;
找了一下原因,发现下面初始化不一样
{
while(root[i]>0)
i=root[i];
return i;
//return root[i]<0?i:find_root(root[i]);
}
void merge(int i,int j)
{
i=find_root(i);
j=find_root(j);
if(i!=j)
{
if(root[i]<root[j])//此时root[i]的绝对值比root[j]大
{
root[i]+=root[j];
root[j]=i;
}
else
{
root[j]+=root[i];
root[i]=j;
}
}
}
int main()
{
using namespace std;
int n,i,j,a,b,d;
char s;
while(cin>>n>>d)
{
memset(work,false,sizeof(work));
memset(root,-1,sizeof(root));//就是这里LOL,直接初始化为-1了。。。
for(i=1;i<=n;++i)
cin>>point[i][0]>>point[i][1];
for(i=1;i<=n;++i)
for(j=1;j<=i;++j)
{
int t=cal(point[i][0],point[i][1],point[j][0],point[j][1]);
if(t<=d*d)
dis[i][j]=dis[j][i]=true;
else
dis[i][j]=dis[j][i]=false;
}
while(cin>>s)
{
if(s=='O')
{
cin>>a;
work[a]=true;
for(i=1;i<=n;++i)
{
if(i!=a&&work[i]&&dis[i][a])
merge(i,a);
}
}
else if(s=='S')
{
cin>>a>>b;
if(find_root(a)==find_root(b))
cout<<"SUCCESS"<<endl;
else
cout<<"FAIL"<<endl;
}
}
}
return 0;
}