#include<iostream>
#include<cstdio>
using namespace std;
const int num=110;
int n,m,cn,rn,bn;//n,无向图顶点数;m,无向图的边数;cn,当前 完全子图中 选择了cn个节点;rn,剩余的节点数;bn,目前找到的团,中所含的最多节点;
int e[num][num];//e[i][j]=1,表示i和j之间有一条无向边。
int x[num],bx[num];//x[i],x[i]=1;表示第i个节点已加入当前完全子图;bx[]对应bn中记录的团所包含的点;bx[i]=1;表示有该节点;
void BackTrack(int i)
{
//处理完n个节点之后,去更新最优解
if(i>n){
if(cn>bn){
//保存最优解;
for(int i=1;i<=n;i++) bx[i]=x[i];
bn=cn;
}
return ;
}
rn=n-i;
//rn=n-i,即为 当前节点之后 还剩余的节点。(i,n]的节点数。
//选择该点:cn:[1:i) , rn:(i,n]的点;
//if cn + 1 + rn > bn 的话, 就有可能更新最优解;
if(cn+1+rn>bn){//限界条件
int f=1;
//判断第i个节点和当前完全子图中的节点,x[k]==1;是否都连接;
for(int k=1;k<=n;k++)
{
if(x[k]&&e[i][k]==0){//约束条件
f=0;break;
}
}
//i和完全子图中的点都连接;
if(f){
//子图中点的数目+1;标记
cn++;
x[i]=1;
BackTrack(i+1);
//取消
x[i]=0;
cn--;
}
}
//cn: [1:i) ; rn: (i:n];
//不选该点;
if(cn+rn>bn){//限界条件
x[i]=0;
BackTrack(i+1);
}
}
int main()
{
//输入无向图的数据
cin>>n>>m;
//第i个点和第i个是相联系的。
for(int i=1;i<=n;i++)
{e[i][i]=1;
x[i]=0;
}
int u,v;
for(int i=1;i<=m;i++)
{
cin>>u>>v;
e[u][v]=e[v][u]=1;
}
BackTrack(1);
//输出方案
cout<<bn<<endl;
for(int i=1;i<=n;i++)
if(bx[i]) cout<<i<<' ';
return 0;
}
/*
样例:
5 7
1 2
2 3
3 5
4 5
1 4
1 5
2 5
*/
回溯法 最大团问题
最新推荐文章于 2023-08-27 22:17:22 发布