1. 程式人生 > 其它 >分支限界——最大團問題

分支限界——最大團問題

技術標籤:演算法

給定有一個無向圖,找出最大團個數。

最大團也就是該圖中最大的完全圖(各頂點之間都有邊)。
在這裡插入圖片描述
演算法思想:設p為所有點集的集合,依次取出p中的頂點作為團的起始點,也就是以該點為起點開始拓展,每次檢視相鄰頂點是否與團內各點聯通,若true,則加入該點。
為了進一步降低時間複雜度,採取記憶化遞迴的方式,從後向前遍歷頂點,用cnt陣列記錄該點以後所成最大團的個數,以此知該點的潛力,達到剪枝的效果。

#include<bits/stdc++.h>
using namespace std;
#define maxm 55
int g[maxm][maxm];//存圖
int
vis[maxm];//存放已選擇的點 int cnt[maxm];//cnt[i]表示用編號>=i的點能組成的最大團的點數 int ans, n; bool dfs(int cur, int num) {//從第cur個點開始向後新增,當前點是第num個 for (int i = cur + 1; i <= n; i++) { if (cnt[i] + num <= ans)//當前點後的所有點組成的最大團的最大點數+已經加入的點數<=當前最佳答案(最好的情況都不可能超過當前最優解,則進行剪枝) return 0; if (g[cur][i])//兩點相鄰 { int
ok = 1; for (int j = 0; j < num; j++)//是否和當前已經加入團的所有點相鄰 if (!g[i][vis[j]]) { ok = 0; break; } if (ok) {//當前點可以加入團中 vis[num] = i; if (dfs(i, num + 1))//第一次dfs成功的一定是最大的 return 1; } } } ans = max(ans, num); return (ans == max(num, ans) ? 0 : 1); } void maxclique
() { for (int i = n; i > 0; i--) { vis[0] = i; dfs(i, 1); cnt[i] = ans; } } int main() { cin >> n; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { cin >> g[i][j]; g[j][i] = g[i][j]; } maxclique(); cout << cnt[1]; return 0; } /* 5 1 1 0 1 1 1 1 1 0 1 0 1 1 0 1 1 0 0 1 1 1 1 1 1 1 */