CodeForces - 839E Mother of Dragons (最大团)

该问题要求在兰尼斯特王国的城堡之间分配一种液体,以最大化墙壁的稳定性。每个城堡可以存放任意数量(包括0或非整数)的液体,墙壁的稳定性由其连接的两个城堡中液体的乘积决定。Jaime Lannister的目标是找到分配液体的方法,使所有墙壁的稳定性之和最大。输入包含一个邻接矩阵,表示城堡之间的连接。解答策略是找到最大的团并平均分配液体,以达到最优解。解决方案涉及使用Bron-Kerbosch算法的优化版本来寻找最大团。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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 1
0 1 0
1 0 0
0 0 0
output
0.250000000000
input
4 4
0 1 0 1
1 0 1 0
0 1 0 1
1 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 1010
bool 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;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值