并查集 hud1213 poj2236

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


用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 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


题目意思是电脑有几个是坏的,给你一个数,表示每个没坏的电脑之间能通信的最大距离,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;
}

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


 

转载于:https://www.cnblogs.com/liebecelery/p/6847177.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值