求一个图中的最大团(全连通分量) n = 40 (中途相遇法)

58 篇文章 1 订阅
54 篇文章 0 订阅

给出一个图,求图中的最大团,n = 40,应该怎么求呢?


我们可以使用中途相遇法,将原有的40个点分为两部分,每部分各20个点。在此之后,我们可以先对前20个点求出暴力求出所有团。设dp[mask]表示当前选择点的状态为mask(状态压缩)时的最大团数量。则在求整体最大团时,若得到后20个点中的当前团为p,找到在前二十个点中所有与p中所有点都有边的点集q,则maxc = max(maxc, dp[q] + p)。这样,我们就可以求出最大团的大小。

另见:http://blog.csdn.net/mosquito_zm/article/details/77170715

cf 题解版:We can find the maximal clique by the "meet in the middle" approach. Divide the vertices of the graph into 2 sets with equal number of vertices in each set(if n is odd, one set will have a vertex more than the other). We can save the maximal clique for each subset of the first set in dp[mask]. Now ,for each clique C in the second set, let v1, ... , vt be vertices in the first set that are connected to all of the vertices of C. Then m = max(m, dp[mask(v1, ... , vt)] + sizeof(C)) (m is size of maximum clique). Note : finding the maximal clique is also possible by a wise brute forces.

cf题目代码如下:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 40;
const int C = 20;
int dp[1 << C];
ll adj[maxn];
int n,m,k,x;
int maxc(){
	for(int i = 0;i < n;i++){
		for(int j = 0;j < n;j++){
			scanf("%d",&x);
			adj[i] |= (ll)(i == j || x) << j;
		}
	}
	for(int i = 1;i < (1 << max(0,n - C));i++){
		int x = i;
		for(int j = 0;j < C;j++)
			if((i >> j) & 1)
				x &= adj[j + C] >> C;
		if(x == i) dp[i] = __builtin_popcount(i);
	}
	for(int i = 1;i < (1 << max(0,n - C));i++)
		for(int j = 0;j < C;j++)
			if((i >> j) & 1)
				dp[i] = max(dp[i], dp[i ^ (1 << j)]);
	int ans = 0;
	for(int i = 0;i < (1 << min(C,n));i++){
		int x = i,y = (1 << max(0, n - C)) - 1;
		for(int j = 0;j < min(C,n);j++)
			if((i >> j) & 1) 
				x &= adj[j] & ((1 << C) - 1),y &= adj[j] >> C;
		if(x != i) continue;
		ans = max(ans, __builtin_popcount(i) + dp[y]);
	}
	return ans;
}
int main()
{
	scanf("%d",&n);scanf("%d",&k);
	int tmp = maxc();
	long double x = (long double) k / tmp;
	ll ans = tmp * (tmp - 1) / 2;
	cout << fixed << setprecision(8) << x * x * ans << '\n';
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值