UVA10608 Friends 题解

0x01 STEP1 读题审题

UVA10608 Friends

题面翻译

读完题就知道,这题用并查集。

本人太弱,就用带权并查集做。

0x02 STEP2 主要步骤

实际上,带权并查集的几种操作并不复杂,是基础并查集的扩展版。

初始化:

for(int i=1;i<=n;i++)
   {
   f[i]=i;
   num[i]=1; //注意这一行,num[i]表示以i为根节点的集合有多少元素
   }

递归找祖宗:

int getf(int x)
{
	if(f[x]==x)return x; //和基础并查集没什么区别
	int k=getf(f[x]);
    f[x]=k;   //路径压缩,降低复杂度
    return f[x];
}

合并:

int merge(int x,int y)
{
	int p1=getf(x);
	int p2=getf(y);
	if(p1!=p2)   //如果不属于同一集合,则合并
       {
       f[p2]=f[p1];
       num[p1]+=num[p2];  //合并后,要把小集合的元素数量加到大集合里
       }
    return 0;
}

这些操作实现完毕后, O ( n ) O(n) O(n) n u m [ i ] num[i] num[i]数组遍历一遍,找最大值即可。

0x03 STEP3 复杂度分析

初始化 O ( n ) O(n) O(n)

并查集最坏 O ( m l o g n ) O(mlogn) O(mlogn)

找最大值 O ( n ) O(n) O(n)

一次操作大约 O ( m l o g n + 2 n ) O(mlogn+2n) O(mlogn+2n)(不省略常数与低次项)

代入计算得约等于 2000000 2000000 2000000 A C AC AC没问题

0x04 STEP4 完整代码

#include 
using namespace std;
int n,m,t,f[300000],num[300000];
int getf(int x)
{
	if(f[x]==x)return x;  //和基础并查集没什么区别
	int k=getf(f[x]);
    f[x]=k;   //路径压缩,降低复杂度
    return f[x];
}

int merge(int x,int y)
{
	int p1=getf(x);
	int p2=getf(y);
	if(p1!=p2) //如果不属于同一集合,则合并
       {
       f[p2]=f[p1];
       num[p1]+=num[p2]; //合并后,要把小集合的元素数量加到大集合里
       }
    return 0;
}

int main() //请从主函数开始阅读程序,这是个好习惯
{
    scanf("%d",&t);
    for(int q=0;q<t;q++)
        {
        int maxn=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            {
            f[i]=i;
            num[i]=1;  //注意这一行,num[i]表示以i为根节点的集合有多少元素
            }
        for(int i=1;i<=m;i++)
            {
            int j,p;
            scanf("%d%d",&j,&p);
            merge(j,p); //合并操作
            }
        for(int i=1;i<=n;i++) //遍历num数组找最大值
            if(num[i]>maxn)maxn=num[i];
        printf("%d\n",maxn);
        }
	return 0;
}

提交记录

0x05 STEP5 扩展训练

P1196 [NOI2002] 银河英雄传说

P2170 选学霸

T h e The The E n d End End

PS:第一篇题解,若有不慎指出敬请谅解。

你可能感兴趣的:(算法,c++)