解題思路:
並查集的簡單應用,對每次修好的電腦對其它已經修好的電腦遍歷,
如果距離小於等於最大通信距離就將他們合併。之後判斷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;
}