- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
7.21晚上加赛 T2.七负我,做这题找到了性质发现需要求最大团,不会,爆搜,打假了,赛后改,对了,但时间复杂度大爆炸,看下发题解,有这么一句话:于是学习了一下.
我们维护三个集合 \(R、P、X\),\(R\) 表示当前正在找的极大团里的点,\(P\) 表示有可能加入当前在找的极大团里的点,\(X\) 表示已经找到的极大团中的点(用来判重),进行以下过程:
初始化 \(R、 X\) 为空集,\(P\) 为包含所有点的集合; 。
将 \(P\) 中顶部元素 \(u\) 点取出,(设 \(Q(u)\) 为所有与 \(u\) 相邻的点)递归集合 \(R ∪{u},P ∩ {Q(u)},X ∩ {Q(u)}\); 。
将 \(u\) 点从集合 \(P\) 中删去,添加到集合 \(X\) 中; 。
不断重复 2~3 操作,直至 \(P\) 为空.
只看算法过程可能不好理解,那么下面是伪代码及分析.
void dfs(R, P, X){
if(P 和 X 均为空) 输出 R 集合为一个极大团
for 从 P 中选取一个点 a,与 a 相连的点集为 Q(a) {
dfs(R 并上 a,P 和 Q(a) 的交集,X 和 Q(a) 的交集)
从 P 中移除 a 点
把 a 点加入 X 集合
}
}
算法主要思路:很简单,我们每次枚举合法的点加入极大团中,合法即为保证该点加入团中,该团仍然是团,接着更新合法点集合(即可能属于在找的团的点集 \(P\) ),不断递归直到该团极大即可.
我们用 \(P\) 集合维护可能包含于目前所在找的极大团的点集,分析 \(P\) 集合是如何更进的: \(R\) 是当前在找的极大团,由于 \(R\) 集合是每次任意从 \(P\) 中取一个点,我们知道团的定义为任意两个点都有边相连,所以若我把当前新选择的点 \(a\) 加入团中,那么 \(R\) 加入 \(a\) 之后,要想保证新 \(P\) 集合中的点可能包含于新 \(R\) 中团,那么需要满足 \(P\) 中的点都与 \(R\) 中任意一点相连。我们已经可以保证原 \(R\) (加入 \(a\) 之前)集合里所有点都与原 \(P\) 中的点相连,所以现在只需添加条件使得新 \(P\) 中的点与 \(a\) 点相连,于是 \(P∩{Q(a)}\) 是新 \(P\) 集合.
找到一个极大团时需要满足 \(P,X\) 集合都为空: \(P\) 为空即再没有点可以加到 \(R\) 集合中,保证在找的团极大;\(X\) 为空保证之前没有找过此团,用来判重.
int to[N][N], mnt; //to[i][j]用来判断 i 到 j 之间是否连边,mnt为最大团中点的个数
int had[N][N], may[N][N], vis[N][N]; //had,may,vis分别表示 当前在找的团中已有的点、可能加入当前在找的团中的点、已经搜过的点(分别对应算法过程的集合 R,P,X)
//had,may,vis的第一维i都表示处于搜索的第i层,第二维j表示相应的点的个数
//d表示当前搜索处于第几层,R、P、X分别表示had,may,vis在该层搜索中点的个数
void Bron_Kerbosch(int d, int R, int P, int X){
if(!P and !X){ mnt = max(mnt, R); return;} //找到一个极大团
for(int i=1; i<=P; i++){
int u = may[d][i]; //从 P 中取点
for(int j=1; j<=R; j++){
had[d+1][j] = had[d][j];
} had[d+1][R+1] = u; //即 R' = R + {u} 的操作
int newP = 0, newX = 0;
for(int j=1; j<=P; j++) // P' = P ∩ Q(u)
if(to[u][may[d][j]]) may[d+1][++newP] = may[d][j];
for(int j=1; j<=X; j++) // X' = X ∩ Q(u)
if(to[u][vis[d][j]]) vis[d+1][++newX] = vis[d][j];
Bron_Kerbosch(d+1, R+1, newP, newX); //递归搜索
may[d][i] = 0, vis[d][++X] = u; //将 u 点从 P 中删去,加入 X 中
}
}
到这里,就已经可以 A 掉那晚加赛的 T2.七负我 了.
#include<bits/stdc++.h>
#define mp make_pair
#define ll long long
using namespace std;
const int N = 50;
int n, m, x, hnt;
int to[N][N];
int had[N][N], may[N][N], vis[N][N];
void Bron_Kerbosch(int d, int R, int P, int X){
if(!P and !X){ hnt = max(hnt, R); return; }
for(int i=1; i<=P; i++){
int u = may[d][i];
for(int j=1; j<=R; j++){
had[d+1][j] = had[d][j];
} had[d+1][R+1] = u;
int newP = 0, newX = 0;
for(int j=1; j<=P; j++)
if(to[u][may[d][j]]) may[d+1][++newP] = may[d][j];
for(int j=1; j<=X; j++)
if(to[u][vis[d][j]]) vis[d+1][++newX] = vis[d][j];
Bron_Kerbosch(d+1, R+1, newP, newX);
may[d][i] = 0, vis[d][++X] = u;
}
}
signed main(){
// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
scanf("%d%d%d", &n, &m, &x);
for(int i=1; i<=m; i++){
int a, b; scanf("%d%d", &a, &b);
to[a][b] = to[b][a] = 1;
}
int num = 0;
for(int i=1; i<=n; i++)
may[1][++num] = i;
Bron_Kerbosch(1, 0, num, 0);
double ans = x * 1.0 / hnt;
ans *= ans;
ans *= ((hnt - 1) * hnt / 2);
printf("%.6lf", ans);
return 0;
}
但是,这个算法还可以通过设定关键点(pivot vertex)\(v\) 进行优化。主要优化原理见 oi-wiki.
int to[N][N], hnt;
int had[N][N], may[N][N], vis[N][N];
void Bron_kerbosch(int d, int R, int P, int X){
if(!P and !X) { hnt = max(hnt, R); return;}
int u = may[d][1];
for(int i=1; i<=P; i++){
int v = may[d][i];
if(to[u][v]) continue;
for(int j=1; j<=R; j++){
had[d+1][j] = had[d][j];
} had[d+1][R+1] = v;
int newP = 0, newX = 0;
for(int j=1; j<=P; j++)
if(to[v][may[d][j]]) may[d+1][++newP] = may[d][j];
for(int j=1; j<=X; j++)
if(to[v][vis[d][j]]) vis[d+1][++newX] = vis[d][j];
Bron_kerbosch(d+1, R+1, newP, newX);
may[d][i] = 0, vis[d][++X] = v;
}
}
最后此篇关于「图论」Bron-kerbosch算法的文章就讲到这里了,如果你想了解更多关于「图论」Bron-kerbosch算法的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
7.21晚上加赛 T2.七负我,做这题找到了性质发现需要求最大团,不会,爆搜,打假了,赛后改,对了,但时间复杂度大爆炸,看下发题解,有这么一句话:于是学习了一下。 Bron-kerbosch
我正在尝试编写 Bron-Kerbosch algorithm 的 C# 实现在图论中,用于查找图中最大大小的团。 理想情况下,该算法会生成一个图列表,其中每个图都代表初始输入图中的最大团。我的代码没
Bron–Kerbosch algorithm是一种列出图的所有最大派系的方法。我最近成功地实现了这个算法只是为了好玩。缺点是该算法是递归的,因此只能在小图上运行,直到堆栈溢出。 应该可以使算法完全迭
我正在尝试理解 Bron-Kerbosch 的算法(带旋转)以在无向图。我有一些问题: 选择枢轴顶点有什么标准吗?我已经看到一些实现选择具有最多邻居的顶点进行优化,而其他实现则简单地选择预期顶点中的第
我在实现 Bron-Kerbosch 算法的 C 版本时遇到了一些问题: 1- 我完全不了解该算法的工作原理。我试图在 Internet 上找到引用资料,但所有这些引用资料都很糟糕,算法示例实现糟糕透
任何人都可以告诉我,我可以在网络上的哪个位置找到有关 Bron-Kerbosch 算法的解释以查找派系或在此处解释其工作原理? 我知道它发表在“算法 457:查找无向图的所有团”一书中,但我找不到描述
我目前正在尝试在 Bron-Kerbosch 算法的 Clojure 实现中正确有效地使用集合和 clojure.set 命名空间,但遇到了困难。 我正在尝试重构我当前的实现 (defn BK [r
维基百科关于 BK clique 发现的伪代码: BronKerbosch2(R,P,X): if P and X are both empty: report R as a
我一直在练习我的 C++ 算法知识,并卡在了标准 BK 实现上。该算法输出了太多派系,我似乎不明白为什么。我将图形表示为邻接表: vector > adjacency_list; 我的 BK 函数如下
简而言之,我的原始代码(用 Ruby 编写)如下所示: # $seen is a hash to memoize previously seen sets # $sparse is a hash of
对于一个大学项目,我正在尝试实现 Bron–Kerbosch algorithm ,即列出给定图中的所有最大团。 我正在尝试实现第一个算法(不旋转),但我的代码在 Wikipedia's exampl
我正在寻找 Bron-Kerbosch algorithm 的 Javascript 实现或 Girvan-Newman algorithm . 基本上,我想在无向图中为最大集团/社区着色。 遗憾的是
我一直在尝试实现 Bron-Kerbosch algorithm在 Rust 中为我的硕士论文。到目前为止一切正常,但是当我尝试从 BTreeSet 更改时到 HashSet出于性能比较的目的,行为变
我是一名优秀的程序员,十分优秀!