并查集三道入门题

题目描述

Today is Ignatius' birthday. He invites a lot of friends. Now it's dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers.

One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.

For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.

输入

The input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.

输出

For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.

样例输入

2
6 4
1 2
2 3
3 4
1 4

8 10
1 2
2 3
5 6
7 5
4 6
3 6
6 7
2 5
2 4
4 3

样例输出

3
2
题意很简单,n个节点,m条边,问这n个点可以分成几组。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1005;
int far[N];
bool vis[N];
int finf(int x)
{
    int a=x;
    vis[a]=true;
    while(x!=far[x]) x=far[x];
    while(a!=far[a])
    {
        vis[a]=true;
        int z=a;
        a=far[a];
        far[z]=x;
    }
    return x;
}
void uion(int a,int b)
{
    int fa=finf(a);
    int fb=finf(b);
    if(fa!=fb) far[fa]=fb;
}
int main()
{
    int n,m,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        int a,b;
        for(int i=1;i<=n;i++)
            far[i]=i;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            uion(a,b);
        }
//        memset(vis,false,sizeof(vis));
//        for(int i=1;i<=n;i++)
//        {
//            if(!vis[i])
//                finf(i);
//        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
//            printf("%d ",far[i]);
            if(far[i]==i)
                ans++;
        }
        printf("%d\n",ans);
    }
}
某市计划建设一个通信系统。按照规划,这个系统包含若干端点,这些端点由通信线缆链接。消息可以在任何一个端点产生,并且只能通过线缆传送。每个端点接收消息后会将消息传送到与其相连的端点,除了那个消息发送过来的端点。如果某个端点是产生消息的端点,那么消息将被传送到与其相连的每一个端点。
为了提高传送效率和节约资源,要求当消息在某个端点生成后,其余各个端点均能接收到消息,并且每个端点均不会重复收到消息。
现给你通信系统的描述,你能判断此系统是否符合以上要求吗?

输入

输入包含多组测试数据。每两组输入数据之间由空行分隔。
每组输入首先包含2个整数N和M,N(1<=N<=1000)表示端点个数,M(0<=M<=N*(N-1)/2)表示通信线路个数。
接下来M行每行输入2个整数A和B(1<=A,B<=N),表示端点A和B由一条通信线缆相连。两个端点之间至多由一条线缆直接相连,并且没有将某个端点与其自己相连的线缆。
当N和M都为0时,输入结束。

输出

对于每组输入,如果所给的系统描述符合题目要求,则输出Yes,否则输出No。

样例输入

4 3
1 2
2 3
3 4

3 1
2 3

0 0

样例输出

Yes
No
题意:n个点,m条边,问这些点能不能组成一棵树。

坑点:题目说了这些点不能组成环(每个端点不会收到重复的消息)

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1005;
int far[N];
//bool vis[N];
int finf(int x)
{
//    vis[x]=true;
    int a=x;
    while(x!=far[x]) x=far[x];
    while(a!=far[a])
    {
//        vis[a]=true;
        int z=a;
        a=far[a];
        far[z]=x;
    }
//    printf("%d ",x);
    return x;
}
void uion(int a,int b)
{
    int fa=finf(a);
    int fb=finf(b);
    if(fa!=fb)
        far[fa]=fb;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)&&(m+n))
    {
//        memset(vis,false,sizeof(vis));
        int a,b,flag=1;
        for(int i=1;i<=n;i++)
            far[i]=i;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            uion(a,b);
        }
        if(m>=n)//判断是否是环
        {
            printf("No\n");
            continue;
        }
        for(int i=2;i<=n;i++)
        {
//            printf("%d ",finf(i));
            if(finf(i)!=finf(i-1))
            {
                flag=0;
                printf("No\n");
                break;
            }
        }
        if(flag)
            printf("Yes\n");
    }
}

题目描述

Mr Wang wants some boys to help him with a project. Because the project is rather complex, the more boys come, the better it will be. Of course there are certain requirements.Mr Wang selected a room big enough to hold the boys. The boy who are not been chosen has to leave the room immediately. There are 10000000 boys in the room numbered from 1 to 10000000 at the very beginning. After Mr Wang's selection any two of them who are still in this room should be friends (direct or indirect), or there is only one boy left. Given all the direct friend-pairs, you should decide the best way.

输入

The first line of the input contains an integer n (0 ≤ n ≤ 100 000) - the number of direct friend-pairs. The following n lines each contains a pair of numbers A and B separated by a single space that suggests A and B are direct friends. (A ≠ B, 1 ≤ A, B ≤ 10000000)

输出

The output in one line contains exactly one integer equals to the maximum number of boys Mr Wang may keep.

样例输入

3
1 3
1 5
2 5
4
3 2
3 4
1 6
2 6

样例输出

4
5
题意:n条边,问这些树中的最大节点个数是多少。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=100000;
int far[N+5],sum[N+5],ans=0;
bool vis[N];
int fin(int x)
{
    if(far[x]!=x) far[x]=fin(far[x]);//路径压缩
    return far[x];
//    return far[x]==x?far[x]:far[x]=fin(far[x]);
}
//这也是路径压缩
//int fin(int x)
//{
//    int a=x;
//    while(x!=far[x]) x=far[x];
//    while(a!=far[a])
//    {
//        int z=a;
//        a=far[a];
//        far[z]=x;
//    }
//    return x;
//}
void uion(int a,int b)
{
    int fa=fin(a);
    int fb=fin(b);
    if(fa!=fb)
    {
        far[fb]=fa;
        sum[fa]+=sum[fb];
        ans=max(ans,sum[fa]);//更新根节点最大值
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        if(!n)
        {
            printf("1\n");
            continue;
        }
        for(int i=1;i<=N;i++)
            far[i]=i,sum[i]=1;
        ans=0;
        int a,b,num=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&a,&b);
//            num=max(num,a);
//            num=max(num,b);
            uion(a,b);
        }
        printf("%d\n",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值