【POJ 2236】Wireless NetWork(并查集应用)

来源:互联网 发布:变态的皇帝知乎 编辑:程序博客网 时间:2024/06/03 15:41

Wireless NetWork


Description
An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computers, but an unexpected aftershock attacked, all computers in the network were all broken. The computers are repaired one by one, and the network gradually began to work again. Because of the hardware restricts, each computer can only directly communicate with the computers that are not farther than d meters from it. But every computer can be regarded as the intermediary of the communication between two other computers, that is to say computer A and computer B can communicate if computer A and computer B can communicate directly or there is a computer C that can communicate with both A and B.

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.


Input
The first line contains two integers N and d (1 <= N <= 1001, 0 <= d <= 20000). Here N is the number of computers, which are numbered from 1 to N, and D is the maximum distance two computers can communicate directly. In the next N lines, each contains two integers xi, yi (0 <= xi, yi <= 10000), which is the coordinate of N computers. From the (N+1)-th line to the end of input, there are operations, which are carried out one by one. Each line contains an operation in one of following two formats:
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.

Output
For each Testing operation, print “SUCCESS” if the two computers can communicate, or “FAIL” if not.


Sample Input
4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4
Sample Output
FAIL
SUCCESS


题意:

已知N台损坏计算机位置坐标(xi,yi),两正常计算机之间能通信的最长距离为d。现在有工作人员,工作人员能进行的操作:
1. O p :修复计算机p
2. S p q:验证两计算机p,q之间能否通信

输入N,d,接下来N组坐标。然后是操作“O p”“S p q”,每次操作“S p q”时输出两计算机之间能通信“SUCCESS”,不能通信“FAIL”。


思路:

又是求两点之间的关系的问题。求关系,即构建联通块,并将其中的关系用pre数组记录下来。这与之前的两道题(HDU 1213-How many tables?&&HDU 1232-畅通工程)求联通块的数量比起来虽然形式不同,但都用到了同一方法—并查集。用并查集思想可以求出两计算机之间的联系,当进行测是否能通信操作时,只需判断两计算机是否有同一根结点即可。

难点在于修复操作如何构建联通块。我们先来看看这段代码

if(control[0]=='O')            {                scanf("%d",&x);                for(int i=0;i<num;i++){                 //计算此点(修复的机器)与前面(相对于数组COUNT)所有点的距离平方 ,与d^2比较,小于则此点与其他点有联系 (同时pre数组也有改变)                     if(pfun(p[COUNT[i]],p[x])<=d*d)                           join(COUNT[i],x); //x,COUNT[i]顺序不同会影响之后Find()的值,但不影响结果                 }                       COUNT[num++]=x;  //用于记录之前进行过修复操作的点的位置(x),point p[x]可求点坐标             }      

现明确一下,COUNT数组用于记录修复过的计算机 。因为操作输入是随机的,无法正常统计哪些计算机刚才已经修理过了。因此需要COUNT数组来记录一下刚才所修复的计算机。

每次输入一个计算机序号(得到位置),接下来的for循环,将之前每一个已经修复过的计算机都遍历一遍,为的是,找出能够与当前计算机通信的,并将当前机器加入到那个联通块中。


代码示例:

#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define MAX 1005struct point{    int x,y;}p[1005];int COUNT[1005];//大数组放在main前 ,,用于记录修复过的机器 int pre[MAX];int Find(int x){    //寻找根结点     int r=x;//让r帮x去找     while(r!=pre[r])    {        r=pre[r];    }    //路径压缩     int i=x,j;//j是临时变量,存i的前驱     while(i!=r)    {        j=pre[i];        pre[i]=r;//i的前驱变为根结点        i=j;//将i的上级(非根)依次赋给i完成上述动作(前驱变为根结点) //即全都拜在根门下     }    //返回根     return r;}int join(int x,int y)   //判断x y是否连通 {    int Fx=Find(x),Fy=Find(y);//分别找x,y的根结点     if(Fx!=Fy)   //根结点不同,即属于不同的联通块       pre[Fx]=Fy;// pre[Fy]=Fx;也可,没有区别。在两不同联通块之间连线 }int pfun(point a,point b){    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}int main(){        int n,d;        scanf("%d %d",&n,&d);//输入数据组数、距离         for(int i=1;i<=n;i++)            scanf("%d %d",&p[i].x,&p[i].y);//输入点坐标         //初始化         for(int i=0;i<MAX;i++)            pre[i]=i;        memset(COUNT,0,sizeof(COUNT));        char control[2];        while(scanf("%s",control)!=EOF)        {            int x,y,num;            if(control[0]=='O')            {                scanf("%d",&x);                for(int i=0;i<num;i++){                 //计算此点(修复的机器)与前面(相对于数组COUNT)所有点的距离平方 ,与d^2比较,小于则此点与其他点有联系 (同时pre数组也有改变)                     if(pfun(p[COUNT[i]],p[x])<=d*d)                           join(COUNT[i],x); //x,COUNT[i]顺序不同会影响之后Find()的值,但不影响结果                 }                       COUNT[num++]=x;  //用于记录之前进行过修复操作的点的位置(x),point p[x]可求点坐标             }            else if(control[0]=='S')            {                scanf("%d%d",&x,&y);                if(Find(x)==Find(y))  //两点根节点相同,则两机器互连                   printf("SUCCESS\n");                  else printf("FAIL\n");            }        }    return 0; } 
原创粉丝点击