5道最基本的并查集- -!

题目就不赘述了。。。分别是HDU1213   HDU1856 HDU1272 HDU1301 HDU1102。。。


1.HDU1213,裸并查集,给你N个人,K组关系,然后认识的可以公用一个桌子,问最后N个人需要用多少张桌子。。。

思路:一开始N个人初始化为互不认识,则桌子数共为N,然后慢慢把相关的人用并查集找出相连,然后如果PRE[I]!=I的时候 每次减一就可以得到结果- -!

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int pre[1005];
int find(int x)
{

    if(x==pre[x])
        return pre[x];
        pre[x]=find(pre[x]);
    return pre[x];
}
void join(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x!=y)
        pre[x]=y;
}
int main()
{
    int t;
    cin>>t;
    int n,m;
    while(t--)
    {
        cin>>n>>m;
        int count=n;
        int i;
        int a,b;
        for(i=0;i<1005;i++)
        {
            pre[i]=i;
        }
        for(i=0;i<m;i++)
        {
            cin>>a>>b;
            join(a,b);
        }
        for(i=1;i<=n;i++)
        {
            if(pre[i]!=i)
                count--;
        }
        cout<<count<<endl;
    }



    return 0;
}
HDU1856:给你N组关系,然后判断能够生成的一个最大集合的元素有多少个。。。记录一下N组关系里面最大的值是哪个,用num[i]记录集合中的元素个数,最后输出最大的就好了。。。唯一的坑就在于- - 当N=0时 是空集。。。要输出1。。。当然 cin cout输出流会TLE- - 。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

const int maxn=10000005;
int pre[maxn],num[maxn];

void init()
{
    int i;
    for(i=1;i<=maxn;i++)
    {
        pre[i]=i;
        num[i]=1;
    }
}
int find(int x)
{
    if(x==pre[x])
        return pre[x];
    pre[x]=find(pre[x]);
    return pre[x];
}

void join(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x!=y)
    {
        pre[x]=y;
        num[y]+=num[x];
    }
}

int main()
{
    int n,a,b,i,sum;
    int t;
    while(scanf("%d",&n)!=EOF)
    {  if(n==0)
      {
        printf("1\n");
        continue;
      }
      t=0;
      init();
      for(i=0;i<n;i++)
      {
          scanf("%d%d",&a,&b);
          if(a>t||b>t)
            t=max(a,b);
            join(a,b);

      }
      sum=0;
      for(i=1;i<=t;i++)
      {
          if(num[i]>=sum)
          sum=num[i];


      }
      cout<<sum<<endl;




    }


    return 0;
}
HDU1272 依然是并查集,用并查集判断是否是回路以及是否是单纯的树还是森林,如果X Y有共同的祖先,那么再把X Y关系加入进来的时候说明成环了 ,而每次将二者关系输入要注意标记他们被征用了而且如果一旦有mark[i]!=0&&pre[i]==i的情况时要注意根节点数+1,如果根节点的个数大于1证明这不是一棵树而形成了一个森林,也是不符合条件的。。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int pre[100005];
int flag;
int mark[100005];
int find(int x)
{

    if(x==pre[x])

    return pre[x];

    pre[x]=find(pre[x]);

    return pre[x];
}

int join(int x,int y)
{
    x=find(x);
    y=find(y);

    if(x!=y)
        pre[x]=y;
    else
        flag=0;
}

int main()
{
    int i,a,b;
    while(cin>>a>>b)
    {
        if(a==-1&&b==-1)
            return 0;
            if(a==0&&b==0)
            {
                cout<<"Yes"<<endl;
                continue;
            }
        for(i=1;i<100005;i++)
        {
            pre[i]=i;
            mark[i]=0;
        }
        mark[a]=mark[b]=1;
        flag=1;
        join(a,b);
        while(cin>>a>>b)
        {
            if(a==0&&b==0)
                break;
            join(a,b);
            mark[a]=mark[b]=1;
        }
        int count=0;
        for(i=1;i<100005;i++)
        {
            if(mark[i]!=0&&pre[i]==i)
                count++;
            if(count>1)
                flag=0;
        }
        if(flag==1)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;

    }


    return 0;
}

HDU1301 裸的最小生成树,可以用PRIM做 但是KRUSKAL做复杂度更低- -而且可以增强对并查集的熟练程度。。。然后唯一要改善的就是原来的都是数字与数字之间的联系,这道题变成了字母与字母,等下转化一下就好- -而且要注意GETCHAR()。。。在每次加入关系的时候将边总数更新~

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

int pre[100];
int n,ans;
struct node{
int s;
int e;
int w;

}edge[10000];

bool cmp(node a,node b)
{
   return a.w<b.w;
}

int find(int x)
{
    if(x==pre[x])
        return pre[x];
    pre[x]=find(pre[x]);
    return  pre[x];
}
bool  join(int x,int y)
{
   x=find(x);
   y=find(y);
   if(x!=y)
   {
       pre[x]=y;
       return true;
   }
   return false;

}
int main()
{
    while(cin>>n)
    {
        if(n==0)
            break;

   int i,j;
    for(i=0;i<=30;i++)
    {
        pre[i]=i;
    }

        ans=0;
        int sum=0;

        for(i=1;i<n;i++)
        {
            char s1;
            getchar();
            cin>>s1;
            int m;
            cin>>m;
            for(j=1;j<=m;j++)
            {
                 char s2;
                 int cost;
                 getchar();
                cin>>s2;
                cin>>cost;
                edge[ans].s=s1-'A';
                edge[ans].e=s2-'A';
                edge[ans].w=cost;
                ans++;
            }
        }
        sort(edge,edge+ans,cmp);
        for(i=0;i<ans;i++)

            if(join(edge[i].s,edge[i].e))
                sum+=edge[i].w;

        cout<<sum<<endl;
    }


    return 0;

}



HDU1102 类似于最小生成树,但不完全一样,他是给了你一些固定的边后,让你在剩下的边里面选取 求出最小总权值的问题,所以先用并查集把已经给定的关系加入,然后再按照权值大小,判断是否成环依次加入,得到最终所要得到的最小权。。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

int pre[105];
int map[105][105];
struct node{

int x;
int y;
int w;

}edge[10000];

bool cmp(node a,node b)
{
    return a.w<b.w;
}


int find(int x)
{

    if(x==pre[x])
        return  pre[x];
    pre[x]=find(pre[x]);
    return pre[x];

}

bool join(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y)
        return false;

        pre[x]=y;
        return true;
}

int main()
{
    int n;
    int i,j,q,a,b,x,y;
    int cost;
    int count;
    while(cin>>n)
    {

        for(i=1;i<=n;i++)
            pre[i]=i;
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                cin>>map[i][j];



        count=0;
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
            {
                edge[count].x=i;
                edge[count].y=j;
                edge[count].w=map[i][j];
                count++;

            }
            sort(edge,edge+count,cmp);
            cin>>q;
           for(i=0;i<q;i++)
            {
                cin>>a>>b;
                a=find(a);
                b=find(b);
                if(a!=b)
                pre[a]=b;



            }
            cost=0;
            for(i=0;i<count;i++)

                if(join(edge[i].x,edge[i].y)!=0)
                    cost+=edge[i].w;


            cout<<cost<<endl;


    }


    return 0;
}

额 这五题都是基础题,厉害的人赶脚一个小时可能就能全部AC,但是我基础较差 花了蛮多时间,代码写挫了,勿怪o(╯□╰)o。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值