POJ2236,Wireless Network,并查集

题意就不解释了;

这道题目怎么用并查集做呢?举个例子,若a,b之间的距离小于d,说明a,b可以通信,用并查集把它们俩连在一起,这时候,倘若,a,c之间的距离也小于d,a,c之间就可以通信,那么b,c也可以通信,用并查集把a,c连在一起,此时,a,b,c连在一棵树上,表明了它们之间互相可以通信(直接或间接);同理,不在同一棵树上的点不能实现通信;


下面这段话写给自己看的 = = :

刚开始,我想到的是用最小生成树来做,后来想想,还是对最小生成树的那个dis数组理解不到位!很容易举出反例:比如a,b之间的距离大于d,a,c之间的距离大于d,b,c之间的距离小于d,那么跑完最小生成树之后,dis[c]的值应该是b到c的距离,小于d,貌似可以通信,但显然是不可以的

#include
#include
#include
#include
using namespace std;
int p[1009];
int find(int x)//递归+压缩路径
{
    return p[x] == x ? x : p[x] = find(p[x]);
}
int n,d;
bool vis[1009];//用来标记哪些电脑修好了
int data[1009][2];//保存坐标值
void Init()//初始化
{
    int i;
    memset(vis,false,sizeof(vis));//刚开始所有的电脑都没有修好
    for (i = 1; i <= n; ++i)
        p[i] = i;
}
bool dis(int a[],int b[])//求两点之间的距离,若距离小于d,则返回true,否则返回false
{
    int x = (a[0] - b[0]) * (a[0] - b[0]);
    int y = (a[1] - b[1]) * (a[1] - b[1]);
    if ((x+y) <= d*d)
        return true;
    return false;
}
int main()
{
    int i,j;
    char ch;
    while (~scanf("%d%d",&n,&d))
    {
        for (i = 1; i <= n; ++i)
            scanf("%d%d",&data[i][0],&data[i][1]);
        Init();
        while (cin>>ch)//用cin输入,这样就可以免去换行带来的不便
        {
            if (ch == 'O')
            {
                cin>>i;
                vis[i] = true;
                for (j = 1; j <= n; ++j)
                {
                    if (vis[j] && dis(data[i],data[j]))//在已经修好的电脑里面,把距离小于d的连在同一棵树上
                    {
                        int x = find(i);
                        int y = find(j);
                        if (x > y) p[x] = y;
                        else if (x < y) p[y] = x;
                    }

                }
            }
            else if (ch == 'S')
            {
                cin>>i>>j;
                int a = find(i);
                int b = find(j);
                if (a == b)//如果要通信的这两点属于同一棵树,那么就可以实现通信
                    printf("SUCCESS\n");
                else
                    printf("FAIL\n");
            }
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构,并查集,POJ2236,Wireless,Network,并查集)