实际上,BGLL算法就是在CNM算法的基础之上,再进一步,通过将CNM算法的结果中处于同一个社团的节点看作一个节点,再使用CNM算法进行社团划分,照此步骤反复迭代,每一次迭代记作一个pass,直到无法继续划分为止(就是在节点合并后,Q也不再增加)。从而尽量减轻因CNM算法的贪心策略造成的社团划分效果不佳,CNM算法实现可参考前文《CNM算法C++实现》
下文示例数据下载链接:facebook_combined
#include<iostream>
#include<cstring>
#include<fstream>
#define N 10000
#define INF 100000000
using namespace std;
int flag,nn,n,M,row,col,A[N][N],B[N][N],book[N],root[N],term[N];
float delta_Q[N][N],a[N],Q,now_Q_change;
void readData();
void initialize();
float themax();
void update_Q_delta();
void printResult();
void solve(int nn);
void formB();
int main()
{
cin>>nn;
fstream readfile;
readfile.open("C:\\Users\\lenovo\\Desktop\\网络科学导论cpp代码\\facebook_combined.txt",ios::in);
if(!readfile.is_open ())
cout << "Open file failure" << endl;
flag=1;
Q=0;
int t=0;
int v1,v2;
while (!readfile.eof()) // 若未到文件结束一直循环
{
readfile >> v1 >> v2;
//cout<<v1<<" "<<v2<<endl;
B[v1][v2]=1;
B[v2][v1]=1;
}
readfile.close(); //关闭文件
while (flag==1)
{
flag=0;
cout<<"第"<<++t<<"次pass"<<endl;
solve(nn);
}
return 0;
}
void solve(int nn)
{
M=0;
n=nn;
memset(book,0,sizeof(book));
memset(a,0,sizeof(a));
readData();
initialize();
now_Q_change=themax();
//cout<<"now_Q_change是:"<<now_Q_change<<endl;
while (now_Q_change>0.0000001)
{
flag=1;
//cout<<"(row,col):("<<row<<","<<col<<")"<<endl;
book[col]=1;
root[col]=row;
//cout<<"root["<<col<<"]:"<<row<<endl;
cout<<"now_Q_change:"<<now_Q_change<<endl;
Q+=now_Q_change;
update_Q_delta();
now_Q_change=themax();
//cout<<"now_Q_change是:"<<now_Q_change<<endl;
}
printResult();
return ;
}
void readData()
{
for (int i=1;i<=n;i++)
root[i]=-1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
A[i][j]=B[i][j];
if (A[i][j]&&i>j)
M+=A[i][j];
}
}
/*
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
cout<<A[i][j]<<" ";
}
cout<<endl;
}
*/
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (A[i][j]!=0)
{
a[i]+=A[i][j];
}
delta_Q[i][j]=-INF;
}
}
for (int i=1;i<=n;i++)
{
a[i]/=(2*M);
//cout<<"a["<<i<<"]:"<<a[i]<<endl;
}
return;
}
void initialize()
{
float temp=0.5;
temp/=M;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (A[i][j]>0)
{
delta_Q[i][j]=temp-a[i]*a[j];
}
else
delta_Q[i][j]=0;
}
}
/*
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
cout<<A[i][j]<<" ";
}
cout<<endl;
}*/
return ;
}
float themax()
{
float curmax=-INF;
for (int i=1;i<=n;i++)
{
if (book[i]==1)
continue;
for (int j=1;j<=n;j++)
{
if (book[j]==1)
continue;
if (curmax<delta_Q[i][j])
{
curmax=delta_Q[i][j];
row=i;
col=j;
}
}
}
//cout<<"(row,col):("<<row<<","<<col<<")"<<endl;
return curmax;
}
void update_Q_delta()
{
//row行消失,只更新col行和col列,col列用col行对称过去即可
for (int i=1;i<=n;i++)
{
if (book[i]==1||col==i)
continue;
if (A[col][i]!=0&&A[row][i]!=0)
{
delta_Q[col][i]=delta_Q[col][i]+delta_Q[row][i];
}
else if (A[col][i]!=0&&A[row][i]==0)
{
delta_Q[col][i]=delta_Q[col][i]-2*a[row]*a[i];
}
else if (A[col][i]==0&&A[row][i]!=0)
{
delta_Q[col][i]=delta_Q[row][i]-2*a[col]*a[i];
}
}
for (int i=1;i<=n;i++)
{
if (book[i]==1)
continue;
delta_Q[i][col]=delta_Q[col][i];
}
a[col]+=a[row];
return ;
}
void printResult()
{
int seq=0;
cout<<"Q值为:"<<Q<<endl;
for (int i=1;i<=n;i++)
{
cout<<"节点"<<i<<"的根为:"<<root[i]<<endl;
if (root[i]==-1)
{
term[i]=++seq;
}
}
for (int i=1;i<=n;i++)
{
int now=i;
while (root[now]!=-1)
{
now=root[now];
}
cout<<"节点"<<i<<"的根是节点:"<<now<<endl;
term[i]=term[now];
}
//至此,seq变量表示新矩阵大小是seq*seq的
nn=seq;
formB();
return ;
}
void formB()
{
memset(B,0,sizeof(B));
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (term[i]!=term[j])//就是说i和j在同一个社团内,他们要形成同一个节点
{
B[term[i]][term[j]]+=A[i][j];
//B[term[j]][term[i]]+=A[i][j];
}
}
}
/*
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
cout<<B[i][j]<<" ";
}
cout<<endl;
}*/
return ;
}
结果的话由于实在太长,所以只截取了部分关键结果(相邻两次迭代连接处),最终一共是迭代了五次。