您的位置:首页 > 编程语言 > Go语言

[Codeforces Round #428 DIV2E (CF839E)] Mother of Dragons

2017-08-13 23:19 471 查看

题意

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

题解

这道题我不会严谨的证明,只能猜一猜,官方题解http://codeforces.com/blog/entry/53815

首先假如整个图是一个点数为k的团,那么每个点的权值分为K/k,最优答案将是K2(k−1)2k。

假如图中存在一个点数为k的团和一个点数为k+1的团,由(k−1)2k=12−12k知,选择k+1的团答案更优。

若存在一个点数为k的团,和差一条边就是k+1的团的伪团(即k+1个点,(k+1)k2−1条边,暂时称作伪团),若给k+1的伪团每点赋值Kk+1,则可以通过做差法求得伪团不如k点的团更优。

基于以上结果,猜测答案取得最优时即为点集为最大团时。

下面就是求最大团的过程了。

由于一般图求最大团是NP-hard的,做的求最大团的题目,只做过2n的搜索。这道题目点数40,显然是双向搜索。于是写了这道题的代码1
436 ms


然而打开status一看,尽是15ms 30ms的代码,于是点开某30ms代码学习,发现了一个没接触过的搜索算法Bron−Kerbosch,于是在网上学习了一下这个算法的姿势,发现朴素的Bron−Kerbosch算法是求所有的极大团,可以求出最大团,但通过一些优化只求最大团可以有效的提高效率。其中两种优化较好,第一种优化是按照退化序枚举点的优化,也就是不断向点集中添点后求最大团,按照这个算法写了代码2
15ms
;第二种是带轴优化,对于一个与当前团内点有边相连但不在当前团内的点u,最大团要么包含u,要么包含与u不相邻的其他点,即选定u后将备选点中与u相邻的点都删去(因为备选点是与当前团中点都相邻的点,如果某备选点与u相邻且被选中,那么必定也要u),所以只需要检验点u与和u不相邻的点即可,根据这个思想写了代码3
15ms


参考资料:

https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm

https://wenku.baidu.com/view/65972e184693daef5ff73d2c.html

http://www.cnblogs.com/yefeng1627/archive/2013/03/31/2991592.html

代码1

/// by ztx
/// blog.csdn.net/hzoi_ztx
#include <bits/stdc++.h>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v)  for(i=v.begin();i!=v.end();i++)
#define r(x)   read(x)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}

#define  kN  45LL
#define  kS  1048576LL

int n, mid, cnt[kN];
bool g[kN][kN];
bool okL[kS], okR[kS];
int siz[kS];

void dfsL(int p=0,int s=0) {
if (p == mid) return;
dfsL(p+1,s);
if (s) for(int i=0;i<mid;i++) if ((s&(1<<i)) && !g[p][i]) return;
s |= (1<<p);
okL[s] = true;
dfsL(p+1,s);
}
void dfsR(int p=mid,int s=0) {
if (p == n) return;
dfsR(p+1,s);
if (s) for(int i=mid;i<n;i++) if ((s&(1<<i-mid)) && !g[p][i]) return;
s |= (1<<p-mid);
okR[s] = true;
dfsR(p+1,s);
}
int calc(int s) {
int i,ret=0;
rep (i,0,mid) if (s&(1<<i)) ret ++ ;
return ret;
}
int main() {
int i, j, k, K, ma, sz;
lf ans;
r(n), r(K);
if (n == 1) {puts("0"); goto END; }
rep (i,0,n) rep (j,0,n) r(g[i][j]);
mid = n>>1;
dfsL();
dfsR();
ma = 0;
for (i = (1<<mid)-1; i >= 0; i -- ) if (okL[i]) siz[i] = calc(i);
for (i = 0; i < (1<<mid); i ++ ) if (siz[i]) {
if (siz[i] > ma) ma = siz[i];
rep (j,0,mid) if (!(i&(1<<j))) {
k = i|(1<<j);
if (siz[k] < siz[i]) siz[k] = siz[i];
}
}
for (i = (1<<n-mid)-1; i >= 0; i -- ) if (okR[i]) {
sz = 0;
rep (j,0,mid) cnt[j] = 0;
rep (j,mid,n) if (i&(1<<j-mid)) {
sz ++ ;
rep (k,0,mid) if (g[j][k]) cnt[k] ++ ;
}
k = 0;
rep (j,0,mid) if (cnt[j] == sz) k |= (1<<j);
if (siz[k]+sz > ma) ma = siz[k]+sz;
}
ans = 1.0*K*K*(ma-1)/ma/2.0;
printf("%.12lf\n", ans);
END: getchar(), getchar();
return 0;
}


代码2

/// by ztx
/// blog.csdn.net/hzoi_ztx
#include <bits/stdc++.h>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v)  for(i=v.begin();i!=v.end();i++)
#define r(x)   read(x)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}

#define  kN  45LL

int n;

namespace MaxClique {
bool g[kN][kN];
int ans, adj[kN][kN], ma[kN];
bool dfs(int now,int dep) {
int i, j, u, v, poi;
rep (i,0,now) {
if (dep+now-i <= ans) return false;
u = adj[dep][i], poi = 0;
if (dep+ma[u] <= ans) return false;
// rec[dep] = u;
rep (j,i+1,now) if (v=adj[dep][j], g[u][v]) adj[dep+1][poi++] = v;
if (dfs(poi,dep+1)) return true;
}
if (dep > ans) {
ans = dep; // upd max clique
return true;
}
return false;
}
int work() {
int i, j, poi;
ans = 0;
Rev (i,n-1,0) {
poi = 0;
rep (j,i+1,n) if (g[i][j]) adj[1][poi++] = j;
//rec[0] = i;
dfs(poi,1);
ma[i] = ans;
}
return ans;
}
}

int main() {
int K, i, j;
lf ans;
r(n), r(K);
using MaxClique::g;
using MaxClique::work;
rep (i,0,n) rep (j,0,n) r(g[i][j]);
i = work();
ans = 1.0*K*K*(i-1)/i/2.0;
printf("%.12lf\n", ans);
END: getchar(), getchar();
return 0;
}


代码3

/// by ztx
/// blog.csdn.net/hzoi_ztx
#include <bits/stdc++.h>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v)  for(i=v.begin();i!=v.end();i++)
#define r(x)   read(x)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}

#define  kN  45LL

int n;

namespace MaxClique {
using std::max;
typedef unsigned long long U;
inline int ctz(U s){return s?__builtin_ctzll(s):8*sizeof(U);}
int ans;
bool g[kN][kN];
U N[kN];
void dfs(U R,U P,U X) {
if (!P && !X) {
ans = max(ans,__builtin_popcountll(R));
return ;
}
if (!P) return;
int pivot = ctz(P|X);
U PP = P&~N[pivot];
for(int u=ctz(PP);u<n;u+=ctz(PP>>(u+1))+1) {
dfs(R|((U)1<<u),P&N[u],X&N[u]);
P ^= ((U)1<<u), X |= ((U)1<<u);
}
}
int work() {
int i, j;
rep (i,0,n) rep (j,0,n) if (g[i][j]) N[i]^=(U)1<<j;
dfs(0,((U)1<<n)-1,0);
return ans;
}
}

int main() {
int K, i, j;
lf ans;
r(n), r(K);
using MaxClique::g;
using MaxClique::work;
rep (i,0,n) rep (j,0,n) r(g[i][j]);
i = work();
ans = 1.0*K*K*(i-1)/i/2.0;
printf("%.12lf\n", ans);
END: getchar(), getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: