并查集部分题目

来源:互联网 发布:香港天文台软件 编辑:程序博客网 时间:2024/04/29 18:21


1 hdu 1232 题目网址

题意:实现任意两个城镇有道路相通,已经修建部分道路,问至少还需修建多少条道路。

思路:连通分量的个数-1

#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>using namespace std;const int maxn = 1000 ;int fa[maxn] , t[maxn] ;int Find(int x){    while(x != fa[x])    {        fa[x] = fa[fa[x]] ;        x = fa[x] ;    }    return x ;}void Union(int x , int y){   int fx = Find(x) ;   int fy = Find(y) ;   if(fx != fy)     fa[fy] = fx ;}int main(){    int N , M , a, b;    while(scanf("%d" , &N)!= EOF &&N)    {        scanf("%d" , &M) ;        for(int i = 1 ; i <= N ; i ++)            fa[i] = i ;        for(int i =0 ; i < M ; i++)        {            scanf("%d%d" , &a ,&b) ;            Union(a ,b) ;        }       memset(t , 0 , sizeof(t) ) ;       for(int i = 1 ; i <= N ; i++)            t[Find(i)] = 1 ;       int ans = 0 ;       for(int i = 1 ; i <= N ; i++)            if(t[i]) ans++ ;       printf("%d\n" , ans - 1) ;    }    return 0;}

hdu 1213 题目网址


题意: 有n个人, 每一桌上的人都相互认识(认识关系可传递),至少需要多少桌可使所有人都坐下

思路:求连通分量数

#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>using namespace std;const int maxn = 1000 ;int fa[maxn] , t[maxn] ;int Find(int x){    while(x != fa[x])    {        fa[x] = fa[fa[x]] ;        x = fa[x] ;    }    return x ;}void Union(int x , int y){   int fx = Find(x) ;   int fy = Find(y) ;   if(fx != fy)     fa[fy] = fx ;}int main(){    int T , N , M , a , b;    scanf("%d" , &T) ;    for(int i = 1 ; i <= T ; i++)    {        scanf("%d%d" , &N, &M) ;        for(int i = 1 ; i <= N ; i++)            fa[i] = i ;        while(M --)        {            scanf("%d%d" , &a, &b) ;            Union(a, b) ;        }        memset(t , 0 , sizeof(t)) ;        for(int i = 1 ; i <= N ; i++)            t[Find(i)] = 1 ;        int ans = 0 ;        for(int i = 1 ; i <= N ; i++)            if(t[i]) ans ++ ;        printf("%d\n" ,ans) ;    }    return 0 ;}

hdu 1598 题目链接

题意:XX星有许多城市,城市之间通过一种奇怪的高速公路SARS(Super Air Roam Structure---超级空中漫游结构)进行交流,每条SARS都对行驶在上面的Flycar限制了固定的Speed,同时XX星人对 Flycar的“舒适度”有特殊要求,即乘坐过程中最高速度与最低速度的差越小乘坐越舒服 ,(理解为SARS的限速要求,flycar必须瞬间提速/降速,痛苦呀 ),
但XX星人对时间却没那么多要求。要你找出一条城市间的最舒适的路径。(SARS是双向的)。

思路:贪心+并查集,对所有道路按照速度进行排序,不断添加道路,当a , b连通时,取道路速度差的最小值。

#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>using namespace std;#define Min(a,b) ( (a) < (b) ? (a) : (b) )const int maxn = 1005 , inf = 1e9;int fa[205] , n , MIN;struct Edge{    int s , t ;    int speed ;};bool cmp(Edge a , Edge b){    return a.speed < b.speed ;}Edge e[maxn] ;void init(int n){    for(int i =1 ; i <= n ; i ++)       fa[i] = i ;}int Find(int a){   while(a != fa[a])   {       fa[a] = fa[fa[a]] ;       a = fa[a] ;   }   return a ;}void Union(int x ,int y){    int fx = Find(x) ;    int fy = Find(y) ;    if(fx != fy)        fa[fy] = fx  ;}int main(){   int m , a ,b ,q ;   while(scanf("%d%d" , &n ,&m) != EOF)   {       for(int i = 0 ; i < m ; i++)          scanf("%d%d%d" , &e[i].s , &e[i].t , &e[i].speed) ;       sort(e , e + m , cmp) ;       scanf("%d" , &q) ;       while(q--)       {           scanf("%d%d" , &a, &b) ;           MIN = inf ;           for(int i = 0; i < m ; i ++)           {               init(n) ;               for(int j = i ; j < m ; j ++)              {                 Union(e[j].s , e[j].t) ;                 if(Find(a) == Find(b))                {                   MIN = Min(MIN , e[j].speed - e[i].speed) ;                   break ;                }             }           }           if(MIN == inf)             printf("-1\n" ) ;           else             printf("%d\n" , MIN) ;       }   }    return 0;}

hdu1856 题目链接

题意:求最大的连通分量的大小

#include<stdio.h>#define N 10000000int pre[N],num[N];int find(int x){int r=x,k=x,j;while(pre[r]!=r)r=pre[r];               while(k!=r){ j=pre[k];             pre[k]=r;                   k=j;                      }    return r;}int join(int x,int y){int fx,fy;fx=find(x);fy=find(y);if(fx!=fy){pre[fx]=fy;num[fy]+=num[fx];}return 0;}int main(){int n,x,y,i,j;while(scanf("%d",&n)!=EOF){for(i=1;i<=N;i++){pre[i]=i;num[i]=1;}while(n--){scanf("%d%d",&x,&y); join(x,y);}int max=1;for(j=1;j<=N;j++){if(num[j]>max)max=num[j];}printf("%d\n",max);}return 0;}

hdu1272 题目链接

题意: 任意两个节若满足有且仅有一条道路相通,则输出“Yes”,否则输出“No”

#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>using namespace std;const int maxn = 100005 ;int edgenum = 0;int f[maxn] , vis[maxn] ;void Init(){    for(int i = 1 ; i <= 100000 ; i ++)        f[i] = i ;}int Find(int x){    while(x != f[x])    {        f[x] ==f[f[x]] ;        x = f[x] ;    }    return x ;}void Union(int x , int y){    int fx = Find(x) ;    int fy = Find(y) ;    if(fx != fy)    {        f[fy] = fx ;        edgenum ++ ;    }}int main(){    //freopen("a.txt" , "r" , stdin) ;    int ok , x , y  , n = 0 , m = 1000000;    while(scanf("%d%d" , &x , &y) != EOF )    {        memset(vis , 0 , sizeof(vis) ) ;        edgenum = 0 ;        n = 0 ;       if( x == -1 && y == -1) break ;       if (x == 0 && y == 0 )       {           printf("Yes\n") ; continue ;       }       Init() ;       Union(x , y) ;       vis[x] = 1 , vis[y] = 1 ;       ok = 1 ;       while(scanf("%d%d" , &x ,&y)!= EOF )       {           if(x == 0 && y == 0) break ;           if(Find(x) == Find(y))            { ok = 0 ;Union(x ,y ) ;}           else Union(x ,y ) ;           vis[x] = 1 , vis[y] = 1 ;       }       int vnum = 0 ;       for(int i = 1 ; i <= 100000 ; i ++)       {           if(vis[i]) vnum ++ ;       }       if(vnum != edgenum + 1) ok = 0 ;       if(ok )  printf("Yes\n") ;       else  printf("No\n") ;    }    return 0;}
hdu 5606链接

题意:n个节点n - 1条边,每条边的权值为0或1,求所有节点i(1 <= i <= n)离节点i最近的节点的数目,并对它们异或操作后输出

思路:求所有连通分量的大小,并对他们进行异或操作

#include <iostream>#include <stdio.h>#include <algorithm>using namespace std;const int maxn = 100005;int fa[maxn] , ans[maxn] ;void Init(){    for(int i = 1 ; i <= 100000 ; i ++)    {        fa[i] = i ;        ans[i] = 1 ;    }}int Find(int x){    if(x == fa[x]) return x ;    else return fa[x] = Find(fa[x]) ;}int Union(int x , int y){   int fx = Find(x) ;   int fy = Find(y) ;   if(fx != fy)   {       fa[fy] = fx ;       ans[fx] += ans[fy] ;       //ans[fy] = ans[fx] ;   }   return 0 ;}int Xor( int a , int b){     return (!a && b) || (a && !b) ;}int main(){    //freopen("a.txt" , "r" , stdin) ;    int t , n , u , v , w ;    scanf("%d" , &t) ;    while(t --)    {        scanf("%d" , &n) ;        Init() ;        for(int i = 1 ; i <= n -1 ; i ++)        {            scanf("%d%d%d" , &u , &v , &w) ;            if(w == 0) Union(u , v) ; //权值为0时,为一个连通分量        }        for(int i = 1 ; i <= n ; i ++) //更新所有的连通分量大小        {            int k = Find(i) ;             ans[i] = ans[k] ;        }        int Ans = ans[1];        for(int i = 2 ; i <= n ; i ++)        {            Ans = Ans ^ ans[i] ;        }        printf("%d\n" , Ans) ;    }    return 0;}

hdu1198 稍微复杂的连通分量表示链接

题意:有11种不同形状的管道,一块田用这11种不同形状的管道覆盖,问这块田中有多少连通分量

思路:本题难点是如何表示连通分量,集合的合并操作怎么表示

#include <iostream>#include <stdio.h>#include <algorithm>using namespace std;const int maxn = 1000 ;int type[11][4] ={   {1 , 0 , 1 , 0} ,   {0 , 1 , 1 , 0} ,   {1 , 0 , 0 , 1} ,   {0 , 1 , 0 , 1} ,   {0 , 0 , 1 , 1} ,   {1 , 1 , 0 , 0} ,   {1 , 1 , 1 , 0} ,   {1 , 0 , 1 , 1} ,   {1 , 1 , 0 , 1} ,   {0 , 1 , 1 , 1} ,   {1 , 1 , 1 , 1}} ;char Farm[maxn][maxn] ;int fa[maxn*maxn + 10] ;int cnt , m , n ;void Init(int n){    for(int i = 1 ; i <=n ; i ++)        fa[i] = i ;    cnt = n ;}int Find(int x){    if(x == fa[x]) return x ;    else return fa[x] = Find(fa[x]) ;}void Union(int ax , int ay , int bx , int by , int dir){    if(ax > m || bx > m ) return ;    if(ay > n || by > n ) return ;    int a = Farm[ax][ay] - 'A' ;    int b = Farm[bx][by] - 'A' ;    bool flag = false ;    if(dir == 0)    {        if(type[a][1] && type[b][0]) flag = true ;    }    else    {        if(type[a][3] && type[b][2]) flag = true ;    }    if(flag )    {        int fx = Find( (ax - 1) * n + ay) ;        int fy = Find( (bx - 1) * n + by) ;        if(fx != fy)        {            fa[fx] = fy ;            -- cnt ;        }    }}int main(){    //freopen("a.txt" , "r" , stdin) ;    while(scanf("%d%d" , &m , &n) != EOF)    {        if(n <0 || m < 0) break ;        Init(n * m) ;        for(int i = 1 ; i <= m ; i ++)            scanf("%s" , Farm[i] + 1) ;        for(int i = 1 ; i <= m ; i ++)        {            for(int j = 1 ; j <= n ; j ++)            {                Union(i , j , i + 1 , j , 1) ;                Union(i , j , i , j + 1 , 0) ;            }        }        printf("%d\n" , cnt) ;    }    return 0 ;}

hdu2473链接

并查集的删除操作

#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>#include <set>#pragma comment(linker, “/STACK:1024000000,1024000000”)using namespace std;const int maxn = 1100006 ;int fa[maxn] , id[maxn] ;set<int> S ;int Find(int x){    if(x == fa[x]) return x ;    else return fa[x] = Find(fa[x]) ;}void Union(int x ,int y){   int fx = Find(id[x]) ;   int fy = Find(id[y]) ;   if(fx != fy)       fa[fx] = fy ;}int main(){    //freopen("a.txt", "r" , stdin) ;    int n , m , kase = 0 , x , y , cnt  ;    char s[10] ;    while(scanf("%d%d" , &n , &m) != EOF)    {  S.clear() ;        if(n == 0 && m == 0) break ;        cnt = n ;        for(int i = 0 ; i < maxn ; i ++)            fa[i] = i ;        for(int i = 0 ; i < n ; i ++)            id[i] = i ;        for(int i = 1 ; i <= m ; i ++)        {            scanf("%s" , s) ;            if(s[0] == 'M')            {                scanf("%d%d" , &x , &y ) ;                Union(x , y) ;            }            if(s[0] == 'S')            {                scanf("%d" , &x) ;                id[x] = cnt ++ ;                //fa[id[x]]=id[x];            }        }        for(int i = 0 ; i < n ; i ++)        {            S.insert(Find(id[i])) ;            //printf("%d " , Find(id[i])) ;        }        //printf("\n") ;        printf("Case #%d: %d\n" , ++kase , S.size()) ;    }    return 0;}


0 0