并查集入门 hud1213 poj2236

来源:互联网 发布:护手霜 知乎 编辑:程序博客网 时间:2024/06/05 14:19

并查集还是很好理解的,应用在求联通块,儿子们找同一个祖先的问题,现在我并查集代码还有点问题的,具体优化还需要继续学习。


用poj的题目(2236)讲一下就行了把应该。http://poj.org/problem?id=2236


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 10 10 20 30 4O 1O 2O 4S 1 4O 3S 1 4

Sample Output

FAILSUCCESS


题目意思是电脑有几个是坏的,给你一个数,表示每个没坏的电脑之间能通信的最大距离,O操作是让一个电脑有用,S问这两个电脑能不能通信,通过别的电脑做桥梁也行。

代码:

#include<iostream>
using namespace std;
//int fa[1005],x[1005],y[1005];
struct ss
{
    int x,y,ft,fa;
}s[1005];
int fi(int x)
{
    if(s[x].fa==x) return x;//fa[x];
    s[x].fa=fi(s[x].fa);
}
void unions(int  cs1,int  cs2,int juli)
{
    int p1=fi(cs1);
    int p2=fi(cs2);
    if((s[cs1].x-s[cs2].x)*(s[cs1].x-s[cs2].x)+ (s[cs1].y-s[cs2].y)*(s[cs1].y-s[cs2].y)<=juli*juli)
        s[p2].fa=p1;
    //cout<<"sssssss"<<s[1].fa<<s[2].fa<<s[3].fa<<s[4].fa<<endl;
}
void  checks(int x,int y)
{
    if(fi(x)!=fi(y))
        cout<<"FAIL"<<endl;
    else
        cout<<"SUCCESS"<<endl;
}
int main( )
{
    int i,n,juli,a,b;
    char ch;
    cin>>n>>juli;
        for(i=1;i<=n;i++)
        {
            s[i].fa=i;
            s[i].ft=0;
        }


        for(i=1;i<=n;i++)
            cin>>s[i].x>>s[i].y;
    while(cin>>ch)
    {


        if(ch=='O')
        {
            cin>>a;
            s[a].ft=1;
            for(i=1;i<=n;i++)
            if(s[i].ft==1&&i!=a)
                unions(i,a,juli);

        }
        else if(ch=='S')
        {
            cin>>a>>b;
            checks(a,b);
        }
    }
    return 0;
}

然后并查集主要是定义一个结构体再写几个函数:

find(避免重名我写成fi)函数:

int fi(int x)
{
    if(s[x].fa==x) return x;  //fa[x];
    s[x].fa=fi(s[x].fa);
}  

//这个函数主要的功能是找x的爸爸,如果x的爸爸 s[x].fa 就是他自己的话就返回x自己。如果不是的话,就递归找下去,让x的爸爸等于 他爸爸的爸爸。 认他爷爷做爸爸,如果再不是...........这里需要停下来仔细推导下过程。


union(~unios)函数:

void unions(int  cs1,int  cs2,int juli)
{
    int p1=fi(cs1);
    int p2=fi(cs2);
    if((s[cs1].x-s[cs2].x)*(s[cs1].x-s[cs2].x)+ (s[cs1].y-s[cs2].y)*(s[cs1].y-s[cs2].y)<=juli*juli)
        s[p2].fa=p1;
    //cout<<"sssssss"<<s[1].fa<<s[2].fa<<s[3].fa<<s[4].fa<<endl;
}

//这个函数呢,就是联合函数啦,首先!这个int  p1=fi(cs1),p2=fi(cs2),是非常重要的,是更新祖先的,之前写我一直忘记,搞的我很难受,后面的if是根据题目需要来写的,上面是如果cs1,cs2这两个点的距离小于题目给的数据,就让cs1和cs2的祖先变成一样的,上面是让cs2的祖先变成cs1的祖先。

check 函数:这个函数相比上面那两个函数就不是那么重要了。也是根据个人习惯和题目来的,写不写无所谓。

void  checks(int x,int y)
{
    if(fi(x)!=fi(y))
        cout<<"FAIL"<<endl;
    else
        cout<<"SUCCESS"<<endl;
}


然后再说下主函数需要处理的数据初始化。


 for(i=1;i<=n;i++)
 {
            s[i].fa=i;
            s[i].ft=0;
  }

// 很简单,就是开始让每个人认做他自己的爹,或者说每个人认他自己做爹。s[i].ft的作用是用来标记的。


嗯,应该没有什么问题了。


再贴个模版题,嘻嘻:hdu 1213:

题目就不放了 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1213

代码:

#include<iostream>
using namespace std;
int fa[1005];
int fi(int x)
{
    if(fa[x]==x)
       return fa[x];
    fa[x]=fi(fa[x]);
}


void unio(int x,int y)
{
    x=fi(x);
    y=fi(y);
    if(fa[x]!=fa[y])//if(x!=y)
        fa[x]=y;
}
int check(int x,int y)
{
    if(fi(x)==fi(y))
        return 1;
    else
        return 0;
}




int main( )
{
    int t,i,j,n,m,x,y,ans;
    cin >> t;
    while(t--)
    {
        cin>>n>>m;
        for(i=1;i<=n;i++)
            fa[i]=i;
        for(j=0;j<m;j++)
        {
            cin>>x>>y;
            unio(x,y);
             //cout << fa[1] <<endl;
        }
        ans=0;
        for(j=1;j<=n;j++)
            if(fa[j]==j) ans++;
        cout<<ans<<endl;
    }
    return 0;
}

最后就判断有几个人认他自己做祖先,就有几个联通块了。


0 0