并查集部分题目


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 10000000
int 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值