算法设计与分析课上,老师布置了一个讲解最大团的分支限界算法的问题,在查阅了资料以后,写的代码。
最大团,就是一个图里所有团中最大的一个。团,一个最大的完全子图(改完全子图不包含在其他更大的完全子图中)。
算法原理:
比如对于一个图g,它已经包含了{1,2}并且,我们知道它是按照1,2的顺序放入的,即最后放入的那个点是2,搜索原图所有的顶点,找到一个点x使得:2与x相连,x与g原先有的顶点相连(x与1相连)。那么对于图g的下一个图h就有{1,2,x}放入队列。继续寻找下一个顶点y。依次类推,直到队列为空。
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
struct node//定义结构体
{
int last;//最后加入的点
int v[10];//v[i]=1表示顶点i已经在该集合中v[i]=0则相反
int num;//顶点个数
node()//构造函数,初始化
{
memset(v,0,sizeof(v));
num=0;
}
};
int ans,n;
int a[11][11];
queue<node*>q;
void bfs(node *head)//分支界限算法
{
while(!q.empty())q.pop();
q.push(head);
int i,j;
while(!q.empty())
{
node *tem=q.front();//取对顶
ans=max(ans,tem->num);
if(ans==n)break;
q.pop();
int t=tem->last;
for(i=1; i<=n; i++)//搜索所有的顶点
{
if(i==t)continue;
if(a[t][i]==1&&tem->v[i]==0)//如果该点还未加入该集合并且该点与最后加入的点有连线
{
for(j=1; j<=n; j++)//判断该点是否与已经加入该集合的每一个点有连线
{
if(tem->v[j]==1&&a[i][j]==0)break;
}
if(j>n)//如果该点与该集合的每一个点有连线,在该集合中加入该点
{
node *nod=new node();
for(int k=1; k<=n; k++)//初始化
{
nod->v[k]=tem->v[k];
}
nod->last=i;
nod->v[i]=1;
nod->num=tem->num+1;
q.push(nod);//新节点推入该队列
}
}
}
}
}
int main()
{
int m,i,j,k;
cout<<"请输入顶点个数";
cin>>n;
for(i=1; i<=n; i++)
{
cout<<"请输入与点 "<<i<<" 相关的所有的点的连线情况:";
for(j=1; j<=n; j++)
{
cin>>a[i][j];
}
}
for(i=0; i<=n; i++)//根节点与所有的点相连
a[i][0]=a[0][i]=1;
node *head=new node();
head->last=0;
ans=0;
bfs(head);
cout<<"最大团的个数为:";
cout<<ans<<endl;
return 0;
}
/*
5
0 1 0 1 1
1 0 1 0 1
0 1 0 0 1
1 0 0 0 1
1 1 1 1 0
*/