给出一个图,求图中的最大团,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;
}