求图的最大团问题
搜索解空间:
1、约束条件:
只要第t个结点和前t-1个结点中被选中的结点都有边相连,则放入团中,否则不能放入
2、限界条件:
当第t个结点不能放入团中时,要判断假设下面的n-t个结点全放入团中加上当前以及放入的结点cn个的和:cn+n-t是否大于最优值bestn,若大于,则有必要继续搜索;
若小于等于,则没必要继续搜索,当前的bestn就是最优值,搜索可以结束了
3、搜索过程:从根节点出发,以深度优先搜索的方式进行,每次搜索一个结点,判断约束条件,满足则继续向其左分支向下继续搜索;如果不满足,则要判断限界条件,如果满足限界条件,则继续向其右子树向下继续搜索,不满足则当前bestn即是最优值,搜索结束。
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 const int N=100; 5 int a[N][N];//图用邻接矩阵表示 6 bool x[N];//存储每个点是否加入团 7 bool bestx[N];//记录每个结点是否放入,记录最优解 8 int bestn;//记录最大值 9 int cn;//当前已放入团中的结点数量 10 int n,m;//n为结点数,m为图中的边数 11 bool Place(int t){//判断第t个结点是否可以放入最大团 12 bool ok=true; 13 for(int j=1;j<t;j++){ 14 if(x[j]&&a[t][j]==0){//x[j]是第j个点放入了最大团中,a[t][j]是前面放入的t-1个结点是否和第t个点有相连边 15 ok=false; 16 break; 17 } 18 } 19 return ok; 20 } 21 void Backtrack(int t){ 22 if(t>n){//到达叶结点 23 bestn=cn;//将当前团个数设为最优值 24 for(int i=1;i<=n;i++){//并寻找最优解:由哪些结点构成 25 bestx[i]=x[i]; 26 } 27 return ; 28 } 29 if(Place(t)){//满足约束条件,进入左子树 30 cn++;//放入 31 x[t]=1;//设为放入 32 Backtrack(t+1);//进入下一层(左子树) 33 cn--;//回溯回来cn-- ,怎么加的怎么减去 34 } 35 if(cn+n-t>bestn){//满足限界条件,进入右子树 36 x[t]=0;//不放入,cn不变 37 Backtrack(t+1);//进入下一层(右子树) 38 } 39 } 40 int main(){ 41 int u,v; 42 cout<<"结点数n:"; 43 cin>>n; 44 cout<<"边数m:"; 45 cin>>m; 46 memset(a,0,sizeof(a)); 47 cout<<"请输入有边相连的两点:"; 48 for(int i=1;i<=m;i++){ 49 cin>>u>>v; 50 a[u][v]=a[v][u]=1; 51 } 52 bestn=0; 53 cn=0; 54 Backtrack(1); 55 cout<<"最大团个数为:"<<bestn<<endl; 56 cout<<"分别为:"; 57 for(int i=1;i<=n;i++) 58 if(bestx[i]==1) 59 cout<<i<<" "; 60 return 0; 61 }