并查集

来源:互联网 发布:电脑445端口怎么关闭 编辑:程序博客网 时间:2024/06/05 00:17

并查集

http://tyvj.cn/Problem_Show.asp?id=1111

描述:

Victoria是一位颇有成就的艺术家,他因油画作品《我爱北京天安门》闻名于世界。现在,他为了报答帮助他的同行们,准备开一个舞会。
Victoria准备邀请n个已经确定的人,可是问题来了:
这n个人每一个人都有一个小花名册,名册里面写着他所愿意交流的人的名字。比如说在A的人名单里写了B,那么表示A愿意与B交流;但是B的名单里不见的有A,也就是说B不见的想与A交流。但是如果A愿意与B交流,B愿意与C交流,那么A一定愿意与C交流。也就是说交流有传递性。
Victoria觉得需要将这n个人分为m组,要求每一组的任何一人都愿意与组内其他人交流。并求出一种方案以确定m的最小值是多少。
注意:自己的名单里面不会有自己的名字。

输入格式:

第一行输入一个n,接下来n行,每i+1行表示为编号为i的人的小花名册名单,名单以0结束。

输出格式;

一个数m。

输入样例:

18
0
18 0
0
0
11 0
0
0
0
0
0
5 0
0
0
0
0
0
0
2 0
输出样例:

16

分析:

这题要用并查集去解。

并查集模版一:

void  init (  )  //集合元素个数{      for ( int i = 0; i < MAX; i++ )                 parent[i] = -1;    //每一个自成一个单元素集合}Find ( int x ) {     if ( parent [x] < 0 ) return x;      else return Find ( parent [x] ); } void Union ( int Root1, int Root2 ) {     //求两个不相交集合Root1与Root2的并        parent[Root1] += parent[Root2];        parent[Root2] = Root1; //将Root2连接到Root1下面}

并查集模版二:

int parent[Max]; //记录结点的双亲 int rank[Max]; //记录结点的深度void init(int n)   //初始化 {  int i;   for(i=0;i<=n;i++)   {  parent[i]=i;      rank[i]=1;    }} int find(int x)    //查找 {  int t=x, temp;   while(parent[x]!=x) //找所属集合,即根结点         x=parent[x];       while(parent[t]!=x)      {   //路径压缩,使深度不为1的点向上浮。       temp=parent[t];     parent[t]=x;               rank[t]=1;      t=temp;      }   return x; }void merge(int x,int y)    //合并 {    int tx=find(x);     int ty=find(y);       if(tx!=ty)  //路径压缩      {  if (rank[tx]<rank[ty])          {  parent[tx]=ty;           rank[ty]+=rank[tx];            rank[tx]=1;        }        else          {  parent[ty]=tx;           rank[tx]+=rank[ty];           rank[ty]=1;        }         } }


代码:

#include <iostream>using namespace std;#define N 204#include<cstring>int map[N][N],n,m,rant[N],parent[N];void init(int n){for(int i=1;i<=n;i++){parent[i]=i;rant[i]=0;}}int find(int x){ if(parent[x]==x) return x; else  return parent[x]=find(parent[x]);}void uion(int u,int v){int fa=find(u);int fb=find(v);if(fa!=fb){if(rant[fa]<rant[fb]){parent[fa]=fb;rant[fb]+=rant[fa];rant[fa]=1;}else{parent[fb]=fa; rant[fa]+=rant[fb]; rant[fb]=1;}m--;}}int main(int argc, char *argv[]){int i ,j;cin>>n;memset(map,0,sizeof(map));for(i=1;i<=n;i++){while(cin>>j,j)map[i][j]=1;}m=n;init(n);for(i=1;i<=n;i++){for(j=1;j<=n;j++)if(map[i][j]==1&&map[j][i]==1){uion(i,j);map[i][j]=0;}}cout<<m<<endl;return 0;}



 

 

 

 

原创粉丝点击