用简单分支限界法解决最大团问题

        今天写算法题时遇到一个  最大团问题  我用了分支限界法求解,分享一下我的做法哈(^-^)

在图论中,完全图需要满足的条件是图中任意两顶点都是连通的,就像这样:

        通俗地说呢:最大团问题其实就是就是给你一个无向图,让你找出这个无向图中顶点数最多的完全图(图中顶点两两连通 )。

        本题使用的分支限界法类似于回溯法,但是回溯法一般用于在解空间中找到所有满足条件的解,而分支限界法则是用于在解空间中找出满足约束条件的最优解。因此一般需要使用优先队列来加快找出最优解的进程或是自己想一个限界函数来剪枝以提高算法的运行效率。

问题描述:一个无向图G中寒顶点个数最多的完全子图成为最大团。输入含n个顶点(编号为1~n),m条边的无向图,求其最大团的顶点个数。

输入描述:输入多个测试用例,每个测试用例的第一行包含两个正整数n,m,接下来m行,每行两个整数s,t 表示顶点 s 与顶点 t 之间有一条边,以输入n=0,m=0结束,规定1<=n<=50并且1<=m<=300

话不多说,代码如下:

#include<iostream>
#define MAXN 51
#define MAXE 301
 
using namespace std;

int n, m;//无向图中顶点个数与边的个数
int a[MAXN][MAXN];//无向图矩阵
int ans;//用于记录当前最优解
int cnt;//当前深度遍历时已经纳入最大团的顶点数目
int x[MAXN];//当前的解向量 (x[i]==1表示将编号为i的顶点放入解向量中)

//dfs函数设计:  i表示正在处理图中编号为i的顶点
void dfs(int i) {
	if (i > n) {//递归出口:  所有顶点都已处理完毕
		if (cnt > ans)//替换最优解
			ans = cnt;

		return;
	}
	bool flag = true;
	for (int j = 1; j < i; j++) {
		if (x[j] == 1 && a[i][j] == 0) {//判断当前顶点i与前 1,2,...,i-1个顶点的连通关系
			flag = false;
			break;
		}
	}
	if (flag) {//如果满足连通条件则将顶点放入解向量中
		x[i] = 1;
		cnt++;
		dfs(i + 1);
        //回溯
		x[i] = 0;
		cnt--;
	}
	if (cnt + n - i >=ans) {//利用一个简单的限界函数进行剪枝
    //只有当当前已经纳入结果的顶点数加上剩余未判断的顶点数大于等于当前最大解时才往下递归
		x[i] = 0;
		dfs(i + 1);
	}

}

int main() {

	int s, t;

	while (true) {
		cin >> n >> m;
		if (n == 0 && m == 0)  break;
		//初始化变量
		memset(a, 0, sizeof a);
		memset(x, 0, sizeof x);
		cnt = 0; ans = 0;


		for (int i = 1; i <= m; i++) {
			cin >> s >> t;
			a[s][t] = 1;
			a[t][s] = 1;
		}
		dfs(1);
		cout << "最大团中的顶点数量为 " << ans << endl;

	}

	return 0;
}

可以使用以下的测试数据:

5 8
1 2
1 3
1 4
1 5
2 4
3 4
3 5
4 5

0 0

最终的结果应该是4

能力有限,令请各位大神赐教ya。

以下是最大团问题分支限界算法的伪代码: ``` maxClique(G): bestClique = [] clique = [] nodes = G.nodes() sortedNodes = sortNodesByDegree(nodes, G) expandCliques(clique, sortedNodes, G, bestClique) return bestClique expandCliques(clique, sortedNodes, G, bestClique): if no nodes left to add: if len(clique) > len(bestClique): bestClique = clique return if len(clique) + len(sortedNodes) <= len(bestClique): return node = sortedNodes.pop(0) expandCliques(clique + [node], getNextNodes(node, sortedNodes, G), G, bestClique) expandCliques(clique, sortedNodes, G, bestClique) getNextNodes(node, sortedNodes, G): return [n for n in sortedNodes if G.has_edge(node, n)] sortNodesByDegree(nodes, G): return sorted(nodes, key=lambda x: G.degree[x], reverse=True) ``` 其中,`maxClique` 函数接收一个无向图 `G` 作为输入,返回最大团。该函数首先初始化 `bestClique` 和 `clique` 两个空列表,分别代表当前最优解和当前搜索路径中的节点。然后,按照节点度数从大到小排序,调用 `expandCliques` 函数进行搜索,并返回 `bestClique`。 `expandCliques` 函数接收当前搜索路径中的节点列表 `clique`、按度数排序后的节点列表 `sortedNodes`、无向图 `G` 和当前最优解 `bestClique`。如果当前节点列表中已经没有可以添加的节点,则判断是否是最优解,并返回。如果添加当前节点后的团大小不足以超过当前最优解,则剪枝。否则,将当前节点添加到搜索路径中,更新 `sortedNodes` 列表,继续搜索。然后,回溯到上一层搜索。 `getNextNodes` 函数接收当前节点和按度数排序后的节点列表 `sortedNodes`、无向图 `G`,返回与当前节点相邻且尚未添加到搜索路径中的节点。 `sortNodesByDegree` 函数按照节点度数从大到小排序,并返回排序后的节点列表。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值