并查集主要是体现在并和查的概念上,这个很重要,判断两个元素是否属于同一个集合,将属于不同的集合合并,不合并不属于相同的集合,这样就可以了。
对于集合个数的判断: 主要是要找的这个节点的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]; }
下面是对两组数据的排序:
根据关键字来进行排序;