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

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 1005
struct 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;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值