参看 并查集的tutorial http://blog.csdn.net/jiyanfeng1/article/details/8083789
参考 基于并查集的算法 http://blog.csdn.net/jiyanfeng1/article/details/39257119
假如已知有n个人和m对好友关系,如果两个人是直接或者间接有好友关系,则认为他们属于同一个朋友圈。写程序判断里面有多少朋友圈。
例如:n = 5, m = 3 r = {(1,2), (2, 3), (4, 5)} 1 2 3 是一个朋友圈, 4 5 是一个朋友圈。
所以输出是2.
下面的算法是基于图论中的深度优先的思想。
#include <STDIO.H>
#include <WINDOWS.H>
int Friends(int n, int m , int* r[]);
int main(int argc,char** argv)
{
int r[5][2] = {{1,2},{4,3},{6,5},{7,8},{7,9}};
printf("有%d个朋友圈。\n",Friends(0,5,(int**)r));
return 0;
}
int Friends(int n, int m, int* r[]) // 注意这里的参数很奇葩
{
int *p = (int*)malloc(sizeof(int)*m*3);
memset(p,0,sizeof(int)*m*3);
int i = 0;
int iCount = 0;
int j = 0;
int * q = (int*)r; // 这里很巧妙 将二维指针 强转为一维指针
for (i=0;i<m;++i)
{
for (j=0;j<2;++j)
{
p[i*3+j]=q[i*2+j]; // 注意这里二维数组向一维数组的转换
}
p[i*3+j] = 0;
}
bool bFlag = false;
for (i=0;i<m;++i)
{
bFlag = false;
if (p[i*3+2]==1)
{
bFlag = true;
}
p[i*3+2] = 1;
for (j=0;j<m;++j)
{
if (i==j)
{
continue;
}
if (p[i*3]==p[j*3] ||
p[i*3] == p[j*3+1] ||
p[i*3+1] == p[j*3+0] ||
p[i*3+1] == p[j*3+1])
{
if (p[j*3+2]==1)
{
bFlag = true;
}
p[j*3+2] = 1;
}
}
if (!bFlag)
{
++iCount;
}
}
free(p);
return iCount;
}
另外一个更加简洁的算法是:基于图论的广度优先算法。
给定保存了朋友关系的数组 r ,然后依次扫描数组 r 中的朋友
如果数组中的一对朋友hash set里面找不到,那么朋友圈个数就加1,并且把这两个人加入到 hash set 里。
如果这一对朋友里的任何一个人,在hash set 里找的到,那么朋友圈个数不变,并把这两个人中另外一个不在hash set里的人加入到hash set 里 (如果两个人都已经在hashet 里,那么就什么都不做。)