暑假训练专题二 并查集的理解 优先队列

 并查集主要是体现在并和查的概念上,这个很重要,判断两个元素是否属于同一个集合,将属于不同的集合合并,不合并不属于相同的集合,这样就可以了。

 对于集合个数的判断: 主要是要找的这个节点的parent值是否等于自身,x==p[x].parent,如果相等则成立。

今天做了 3道并查集的问题~~

了解了并查集用到的三个子函数,很有用:

1:数组数据的初始化。

void Make_set()
{
  int i;
   for(i=0;i<n;i++)
   {
      p[i].data=i;
      p[i].rank=0;
      p[i].parent=i;             
   }
}

2:优化后对树的根结点的查找。

int Find(int x)
{
  if(x!=p[x].parent) p[x].parent=Find(p[x].parent);
  return p[x].parent;
}

3:优化后的合并树,是按照秩(树的高度)来合并的。

void Union(int x,int y)
{
  x=Find(x);
  y=Find(y);
  if(x!=y){
            if(p[x].rank>p[y].rank){p[y].parent=x;}
            else {
                  p[x].parent=y;
                  if(p[x].rank==p[y].rank)p[y].rank++;                   
                 }
           }     
}

这是用到的三个代码模版。

下面开始 对例题尽心分析。

杭电1232 畅通工程 就是对并查集的简单应用。

#include<stdio.h>
#include<string.h>
typedef struct node{
              int data;
              int rank;
              int parent;            
                    }UFSTree;
              UFSTree p[1010];

void Make_set(int n);
int Find(int x);
void Union(int x,int y);
int a[1010];
int main()
{
  int n,m,road1,road2,i,j,k,num,flag;
  while(scanf("%d %d",&n,&m)&&n!=0)
  {
    if(m==0){printf("%d\n",n-1);continue;} 
    Make_set(n);
    for(i=1;i<=m;i++)
    {
      scanf("%d %d",&road1,&road2);
      Union(road1,road2);                 
    }
    j=0;
       memset(a,0,sizeof(a));
    a[j]=Find(1);j++;

 
   for(i=2;i<=n;i++)
   {
      flag=0;
      num=Find(i);

      for(k=0;k<j;k++)
      {
       if(a[k]==num){flag=1;break;}                
      }               
      if(flag==0){a[j]=num;j++;}
   } 

   printf("%d\n",j-1); 
                    
  }    
    
}

 void Make_set(int n)
 {
  int i;
  for(i=1;i<=n;i++)
  {
    p[i].data=i;
    p[i].rank=0;
    p[i].parent=i;                
  }   
 }

int Find(int x)
{
  if(x!=p[x].parent) p[x].parent=Find(p[x].parent);
   return p[x].parent; 
}

void Union(int x,int y)
{

  x=Find(x);
  y=Find(y);

  if(x!=y){
           if(p[x].rank>p[y].rank){p[y].parent=x;}
           else {
                p[x].parent=y;
                if(p[x].rank==p[y].rank){
                                     p[y].rank++;   
                                       }
                }
           }   
}

还有就是 poj 2524 Ubiquitous Religions和 这道题完全类似。

还有一道是 poj The Suspects 有略微的变型~~要注意。

 

优先队列:

是按从大到小的顺序输出的。

直接进行输入输出,进行排序;

#include<iostream>
#include<queue>
using namespace std;
int main()
{
  int a[10]={4,3,2,5,4,2,3,2,10,9},i;
  priority_queue<int> qi;
  for(i=0;i<10;i++)
  {
    qi.push(a[i]);                 
  }    
   for(i=0;i<10;i++)
   {
     cout<<qi.top()<<" ";
     qi.pop();                 
   } 
}

得出的结果:

 

 下面是对其尽心逆着排序:即从小到大输出:

#include<iostream>
#include<queue>
using namespace std;
int main()
{
   priority_queue<int ,vector<int>, greater<int> >  q2;
   int i,a[9]={4,3,2,1,5,6,7,8,9};
   for(i=0;i<9;i++)
   {
      q2.push(a[i]);              
   }    
   for(i=0;i<9;i++)
   {
      cout<<q2.top()<<" ";
      q2.pop();                 
   } 
    
    cin>>a[i];
}

下面是对两组数据的排序:

根据关键字来进行排序;

 

 

 

 

转载于:https://www.cnblogs.com/ysh-blog/archive/2012/07/02/2573697.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值