CodeForces

来源:互联网 发布:夏河淘宝日货是正品吗 编辑:程序博客网 时间:2024/06/14 17:39


E. Mother of Dragons
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

There are n castles in the Lannister's Kingdom and some walls connect two castles, no two castles are connected by more than one wall, no wall connects a castle to itself.

Sir Jaime Lannister has discovered that Daenerys Targaryen is going to attack his kingdom soon. Therefore he wants to defend his kingdom. He has k liters of a strange liquid. He wants to distribute that liquid among the castles, so each castle may contain some liquid (possibly zero or non-integer number of liters). After that the stability of a wall is defined as follows: if the wall connects two castles a and b, and they contain x and y liters of that liquid, respectively, then the strength of that wall is x·y.

Your task is to print the maximum possible sum of stabilities of the walls that Sir Jaime Lannister can achieve.

Input

The first line of the input contains two integers n and k (1 ≤ n ≤ 401 ≤ k ≤ 1000).

Then n lines follows. The i-th of these lines contains n integers ai, 1, ai, 2, ..., ai, n (). If castles i and j are connected by a wall, then ai, j = 1. Otherwise it is equal to 0.

It is guaranteed that ai, j = aj, i and ai, i = 0 for all 1 ≤ i, j ≤ n.

Output

Print the maximum possible sum of stabilities of the walls that Sir Jaime Lannister can achieve.

Your answer will be considered correct if its absolute or relative error does not exceed 10 - 6.

Namely: let's assume that your answer is a, and the answer of the jury is b. The checker program will consider your answer correct, if .

Examples
input
3 10 1 01 0 00 0 0
output
0.250000000000
input
4 40 1 0 11 0 1 00 1 0 11 0 1 0
output
4.000000000000
Note

In the first sample, we can assign 0.5, 0.5, 0 liters of liquid to castles 1, 2, 3, respectively, to get the maximum sum (0.25).

In the second sample, we can assign 1.0, 1.0, 1.0, 1.0 liters of liquid to castles 1, 2, 3, 4, respectively, to get the maximum sum (4.0)



题意:给出n40个点的邻接矩阵,要求给每个点赋值,使得点的权值和为K,每条边权值为两端点点权的乘积,最大化边的权值和。

思路:

Lemma : Let G be a simple graph. To every vertex of G we assign a nonnegative real number such that the sum of the numbers assigned to all vertices is 1. For any two connected vertices (by an edge), compute the product of the numbers associated to these vertices. The maximal value of the sum of these products is when assign equal numbers to a maximal clique (a subgraph that all of its vertices are connected to each other) and 0 to the rest of the graph.

简而言之就是直接把K平均分给最大团里的点

转自:点击打开链接

首先假如整个图是一个点数为k的团,那么每个点的权值分为K/k,最优答案将是K2(k1)2k。 
假如图中存在一个点数为k的团和一个点数为k+1的团,由(k1)2k=1212k知,选择k+1的团答案更优。 
若存在一个点数为k的团,和差一条边就是k+1的团的伪团(即k+1个点,(k+1)k21条边,暂时称作伪团),若给k+1的伪团每点赋值Kk+1,则可以通过做差法求得伪团不如k点的团更优。 
基于以上结果,猜测答案取得最优时即为点集为最大团时。 
下面就是求最大团的过程了。 
由于一般图求最大团是NP-hard的,做的求最大团的题目,只做过2n的搜索。这道题目点数40,显然是双向搜索。于是写了这道题的代码1436 ms。 
然而打开status一看,尽是15ms 30ms的代码,于是点开某30ms代码学习,发现了一个没接触过的搜索算法BronKerbosch,于是在网上学习了一下这个算法的姿势,发现朴素的BronKerbosch算法是求所有的极大团,可以求出最大团,但通过一些优化只求最大团可以有效的提高效率。其中两种优化较好,第一种优化是按照退化序枚举点的优化,也就是不断向点集中添点后求最大团,按照这个算法写了代码215ms;第二种是带轴优化,对于一个与当前团内点有边相连但不在当前团内的点u,最大团要么包含u,要么包含与u不相邻的其他点,即选定u后将备选点中与u相邻的点都删去(因为备选点是与当前团中点都相邻的点,如果某备选点与u相邻且被选中,那么必定也要u),所以只需要检验点u与和u不相邻的点即可,根据这个思想写了代码315ms。 

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int maxn = 1e2;int best, num[maxn], gra[maxn][maxn], n;bool dfs(int *adj, int tot, int cnt){    int tmp[maxn];    if(tot == 0)    {        if(best < cnt)        {            best = cnt;            return true;        }        return false;    }    for(int i = 0; i < tot; i++)    {        if(cnt+tot-i <= best)            return false;        if(cnt+num[adj[i]] <= best)            return false;        int k = 0;        for(int j = i+1; j < tot; j++)            if(gra[adj[i]][adj[j]])                tmp[k++] = adj[j];        if(dfs(tmp, k, cnt+1)) return true;    }    return false;}int MaxClique(){    int adj[maxn];    best = 0;    if(n <= 0) return 0;    for(int i = n-1; i >= 0; i--)    {        int k = 0;        for(int j = i+1; j < n; j++)            if(gra[i][j]) adj[k++] = j;        dfs(adj, k, 1);        num[i] = best;//        cout << k << endl;    }    return best;}int main(){    int K;    scanf("%d%d", &n, &K);    for(int i = 0; i < n; i++)        for(int j = 0; j < n; j++)            scanf("%d", &gra[i][j]);    int tmp = MaxClique();//    cout << tmp << endl;    double res = 0.5 * K * K * (tmp - 1) / tmp;    printf("%.8f\n", res);    return 0;}

另一种代码:

#include<cstdio>#include<cstring>#define N 1010bool flag[N], a[N][N];int ans, cnt[N], group[N], n, vis[N];// 最大团: V中取K个顶点,两点间相互连接// 最大独立集: V中取K个顶点,两点间不连接 // 最大团数量 = 补图中最大独立集数 bool dfs( int u, int pos ){    int i, j;    for( i = u+1; i <= n; i++){        if( cnt[i]+pos <= ans ) return 0;        if( a[u][i] ){             // 与目前团中元素比较,取 Non-N(i)             for( j = 0; j < pos; j++ ) if( !a[i][ vis[j] ] ) break;             if( j == pos ){     // 若为空,则皆与 i 相邻,则此时将i加入到 最大团中                 vis[pos] = i;                if( dfs( i, pos+1 ) ) return 1;                }            }    }        if( pos > ans ){            for( i = 0; i < pos; i++ )                group[i] = vis[i]; // 最大团 元素             ans = pos;            return 1;        }        return 0;} void maxclique(){    ans=-1;    for(int i=n;i>0;i--)    {        vis[0]=i;        dfs(i,1);        cnt[i]=ans;    }}


原创粉丝点击