并查集

首先要熟练并查集基本模板:

 1 #include <stdio.h>
 2 
 3 const int MAXN = 100; /*结点数目上线*/
 4 int pa[MAXN];    /*p[x]表示x的父节点*/
 5 int rank[MAXN];    /*rank[x]是x的高度的一个上界*/
 6 
 7 void make_set(int x)
 8 {/*创建一个单元集*/
 9     pa[x] = x;
10     rank[x] = 0;
11 }
12 
13 int find_set(int x)
14 {/*带路径压缩的查找*/
15     if(x != pa[x])
16         pa[x] = find_set(p[x]);
17     return pa[x];
18 }
19 
20 /*按秩合并x,y所在的集合*/
21 void union_set(int x, int y)
22 {
23     x = find_set(x);
24     y = find_set(y);
25     if(rank[x] > rank[y])/*让rank比较高的作为父结点*/
26         pa[y] = x;
27     else 
28     {
29         pa[x] = y;
30         if(rank[x] == rank[y])
31             rank[y]++;
32     }
33 }

例题:POJ 1611
哟呵呵,果然自己打一遍还是出现了问题,在哪里呢,就是在初始化的地方啊!!!!!
并查集一个很重要的地方就是初始化
fa[i]=i;rank[i]=0; //啦啦啦啦啦啦,啦啦啦啦啦

2014.11.26

最近一直在看并查集,感觉小有收获,嘿嘿~
并查集要分析好,代码不是很长
注意在合并的时候要做更新

在求最小生成树的时候kruskal和并查集是很好的结合

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stdlib.h>
#define N 105
#define INF 0xfffffff
using namespace std;
int f[N];
typedef struct
{
    int x,y,len;
}Edge;
Edge edge[N];
int find(int x)
{
    return f[x]=f[x]==x?x:find(f[x]);
}
int cmp(const void *a,const void *b)
{
    return ((Edge *)a)->len>((Edge *)b)->len?1:-1;
}

int n,m;
int kruskal(int o)   //here.the kruskal is not as difficult as i thought.oh yeah!
{
    int cnt=0;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=o;i<m;i++)
    {
        int f1=find(f[edge[o].x]);
        int f2=find(f[edge[o].y]);
        {
            f[f1]=f2;
            cnt++;
        }
        if(cnt==n-1) return edge[i].len-edge[o].len;
    }
    return INF;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0) break;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].len);
        }
        qsort(edge,m,sizeof(edge[0]),cmp);
        int ans=INF;
        for(int i=0;i<=m-n+1;i++)
        {
            int k=kruskal(i);
            if(k<ans) ans=k;
        }
        if(ans==INF) puts("-1");
        else printf("%d\n",ans);

    }
}
find them catch them:
#include<cstdio>
#include<cstring>
#define N 100000+10
int f[N],c[N];
int n,m;
int find(int x)
{
    if(f[x]==x) return x;
    int t=f[x];
    f[x]=find(f[x]);
    c[x]=(c[x]+c[t])%2;  //解题关键
    return f[x];
}
void make(char s,int x,int y)
{
    int f1=find(x);
    int f2=find(y);
    if(f1!=f2)
    {
        if(s=='A')
            {printf("Not sure yet.\n");return;}
            f[f1]=f2;
            if((c[x]+c[y])%2==0)
                c[f1]=1;//这里错了!!!好好思考一下
    }
    else
    {
        if(s=='A')
        {
            if(c[x]==c[y]) printf("In the same gang.\n");
            else printf("In different gangs.\n");
            return;
        }
        return;
    }

}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++) f[i]=i;
        memset(c,0,sizeof(c));
        for(int i=0;i<m;i++)
        {
            char s[5];
            int a,b;
            scanf("%s",s);
            scanf("%d%d",&a,&b);
            make(s[0],a,b);
        }
    }

}

/*
20
20 20
D 2 5
D 3 5
D 1 4
D 1 2
A 4 1
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值