最大团算法(codeforces839E)

时间:2021-05-15 20:26:39

题意理解玩,YY一下,就知道要把K平均分给最大团里面的每个点,然后乘积和就是答案。


最大团就是有n个点的完全图,完全图就是n个点有n*(n-1)/2条边的图、有高效算法求的。。

//最大独立集:一个图中最大的互相没有边相连的点集。
//结论:原图的最大独立集等于补图的最大团
const int maxn=1010;
int best;
int num[maxn];
// int x[maxn];
int path[maxn];
int g[maxn][maxn], n;
bool dfs( int *adj, int total, int cnt ){ // total: 与u相连的顶点数量 , cnt表示当前团的数量
int i, j, k;
int t[maxn];
if( total == 0 ){ // 当此团中最后一个点 没有 比起序号大 的顶点相连时
if( best < cnt ){ // 问题1:best为最大团中顶点的数量
// for( i = 0; i < cnt; i++) path[i] = x[i];
best = cnt; return true;
}
return false;
}
for( i = 0; i < total; i++){ // 枚举每一个与 u 相连的顶点 adj[i]
if( cnt+(total-i) <= best ) return false; // 剪枝1, 若当前 顶点数量cnt 加上还能够增加的最大数量 仍小于 best则 退出并返回false
if( cnt+num[adj[i]] <= best ) return false; // 剪枝2, 若当前 顶点数量cnt 加上 包含adj[i]的最大团顶点数 仍小于 best则 退出并返回false
// x[cnt] = adj[i];
for( k = 0, j = i+1; j < total; j++ ) // 扫描 与u相连的顶点 中与 adj[u]相连的顶点 并存储到 数组 t[]中,数量为k
if( g[ adj[i] ][ adj[j] ] )
t[ k++ ] = adj[j];
if( dfs( t, k, cnt+1 ) ) return true;
} return false;
}
int MaximumClique(){
int i, j, k;
int adj[maxn];
if( n <= 0 ) return 0;
best = 0;
for( i = n-1; i >= 0; i-- ){
// x[0] = i;
for( k = 0, j = i+1; j < n; j++ )// 遍历 [i+1, n] 间顶点,
if( g[i][j] ) adj[k++] = j;
dfs( adj, k, 1 ); // *adj, total, cnt
num[i] = best; // 得出顶点 i, 出发构成最大团 中顶点数量
}
return best;
}
int main()
{
int k;
cin >> n >> k;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
scanf("%d", &g[i][j]);
int t = MaximumClique();
double ans = 0.5 * k * k * (t - 1) / t;
printf("%.8lf\n", ans);
return 0;
}