Borůvka算法

前几天才知道除了primprimprim和kruskalkruskalkruskal以外第三种求无向图MST的算法。

适用情况

平均 O(V+E)O(V+E)O(V+E),最坏 O((V+E)logV)O((V+E)logV)O((V+E)logV)。
因为没有kruskalkruskalkruskal好写,所以一般不用于MST裸题。
相对于其他两种算法,适于处理边权由连接的两个点的点权通过某种计算方式得出的情况。

前置知识点

并查集、连通块

流程

  1. 对每个连通块,处理出与其他连通块连接的最小代价,并记录这条边。
  2. 连接所有连通块与其最小连接代价的连通块,并将该边边权计入。
  3. 若剩余连通块数量大于1,重复上述步骤。

代码

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
//#define int ll
const int maxn=2e5+10,inf=0x3f3f3f3f,mod=1000000007;
const ll INF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-9;
int fa[maxn];
int findfa(int x)
{if(fa[x]!=x)fa[x]=findfa(fa[x]);return fa[x];
}
bool Merge(int x,int y)
{int a=findfa(x),b=findfa(y);if(a==b)return 0;if(a<b)fa[b]=a;elsefa[a]=b;return 1;
}
struct edge
{int u,v,w;edge(){}edge(int u,int v,int w):u(u),v(v),w(w){}
};
vector<edge> E;
int boruvka(int n)
{for(int i=1;i<=n;i++)//n个连通块fa[i]=i;int ans=0;vector<int> cost(n+1),rec(n+1);vector<bool> vis(E.size(),false);while(1){for(int i=1;i<=n;i++)cost[i]=inf;//初始化为infint cur=0;//统计不同连通块for(int i=0;i<E.size();i++){int a=findfa(E[i].u),b=findfa(E[i].v),w=E[i].w;if(a==b)continue;cur++;//记录a,b两个连通块连接的最小代价if(w<cost[a])cost[a]=w,rec[a]=i;//记录最小联通代价与相应边if(w<cost[b])cost[b]=w,rec[b]=i;}if(cur==0)break;for(int i=1;i<=n;i++){//最坏情况是剩余连通块数目减少一半if(cost[i]<inf&&!vis[rec[i]])//与i相接的权值最小的边未加入{Merge(E[rec[i]].u,E[rec[i]].v);//连接两个连通块ans+=E[rec[i]].w;vis[rec[i]]=true;//防止重复计算}}}return ans;
}
signed main(int argc, char const *argv[])
{std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);#ifdef DEBUGfreopen("input.in", "r", stdin);// freopen("output.out", "w", stdout);#endifint n,m;cin>>n>>m;for(int i=1,u,v,w;i<=m;i++){cin>>u>>v>>w;E.push_back({u,v,w});}cout<<boruvka(n)<<endl;return 0;
}

Xor-MST

题意

思路

异或最值问题,套一个trie,如果对这个套路不熟悉,请先做CF923C Perfect Security。
虽然已经没了Borůvka的形但是思想还在。
首先我们对所有点权排序并去重,因为相同的值异或为0,在图中必然是这些点相连且没有贡献,所以我们不用考虑这部分。
将剩下的点权插入trie,从根节点到叶子的一条路径就代表一个点权,叶子结点的数量就代表点权的数量。
初始时每个叶子都代表一个连通块,求解这个问题就是不断连接这些连通块的过程。
对于trie上的节点xxx,如果其左右子树都存在,那么就必须找一条边连接其左右子树,若xxx的所处位数为www,则这条边必有1<<w1<<w1<<w的贡献,对于www之前的位数,因为xxx到根节点路径相同异或值都为0;对于[w−1,0][w-1,0][w−1,0]的位数,这部分的贡献要对trie进行搜索来得到。
此时xxx左右子树已经联通,回溯继续向上处理即可。
checkcheckcheck最坏情况下一次遍历整个trie树,O(nlogn)O(nlogn)O(nlogn),最多合并nlognnlognnlogn次。
整体时间复杂度O(nlog2n)O(nlog^2n)O(nlog2n)。

代码

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
//#define int ll
const int inf=0x3f3f3f3f,mod=1000000007;
const ll INF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-9;
//#define DEBUG//#define lowbit(x) ((x) & -(x))//<<setiosflags(ios::fixed)<<setprecision(9)
void read(){}
template<typename T,typename... T2>inline void read(T &x,T2 &... oth) {x=0; int ch=getchar(),f=0;while(ch<'0'||ch>'9'){if (ch=='-') f=1;ch=getchar();}while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}if(f)x=-x;read(oth...);
}
const int maxn = 200005, M = 2;
int val[maxn],trie[maxn<<5][M],siz[maxn<<5],tot;
void init()
{tot=1;
//  memset(trie[0],0,sizeof(trie[0]));
//  memset(isw,0,sizeof(isw));
}
void Insert(const int key)//rt传入0
{//trie插入模式串int rt=0;for(int i=30;i>=0;i--){int id = (key>>i)&1;if(!trie[rt][id])trie[rt][id]=tot++;rt = trie[rt][id];}
}
ll check(int x,int y,int w)//启发式,最多向下2^w次?,但最多1e5个节点
{//在x子树和y子树上求得一个最小异或值ll ret=LLONG_MAX;if(trie[x][0]&&trie[y][0])//尽量先使高位相同ret=min(ret,check(trie[x][0],trie[y][0],w-1));if(trie[x][1]&&trie[y][1])ret=min(ret,check(trie[x][1],trie[y][1],w-1));if(ret==LLONG_MAX){if(trie[x][0]&&trie[y][1])//w位此时一定为1了ret=min(ret,check(trie[x][0],trie[y][1],w-1))+(1<<w);if(trie[x][1]&&trie[y][0])ret=min(ret,check(trie[x][1],trie[y][0],w-1))+(1<<w);if(ret==LLONG_MAX)//说明两边没有节点return 0;}return ret;
}
ll dfs(int x,int w)//节点x开始搜索,右数第w位
{//从高位向下dfsif(w<0)//只有根节点为0return 0;if(trie[x][0]&&trie[x][1])//都存在,找最小边连接两个连通块return (1<<w)+check(trie[x][0],trie[x][1],w-1)+dfs(trie[x][0],w-1)+dfs(trie[x][1],w-1);else if(trie[x][0])//左面存在return dfs(trie[x][0],w-1);else//右面存在return dfs(trie[x][1],w-1);
}
signed main(int argc, char const *argv[])
{std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);#ifdef DEBUGfreopen("input.in", "r", stdin);// freopen("output.out", "w", stdout);#endifint n,ans=0;init();cin>>n;for(int i=1;i<=n;i++)cin>>val[i];sort(val+1,val+n+1);n=unique(val+1,val+n+1)-val-1;//去重是因为相同值异或为0,没必要再计算for(int i=1;i<=n;i++)Insert(val[i]);cout<<dfs(0,30)<<endl;return 0;
}

Borůvka算法与异或生成树相关推荐

  1. Codeforces.888G.Xor-MST(Borůvka算法求MST 贪心 Trie)

    题目链接 \(Description\) 有一张\(n\)个点的完全图,每个点的权值为\(a_i\),两个点之间的边权为\(a_i\ xor\ a_j\).求该图的最小生成树. \(n\leq2*10 ...

  2. 算法笔记-异或的使用、异或算法面试题、详细解析、异或的理解与其使用规律

    1. 异或的定义 相同为0,不同为1 或者换种说法,异或是不进位的相加,比方说,0与1异或,看做是0+1为1:1与1异或,看做是1+1=0,本来进位是10,但是不要进位,即为0 2. 异或使用规律 1 ...

  3. prim算法_图的生成树之最小生成树(Prim)

    树一般来说是基于图而生的,而树是一种特殊的图:无环连通图. 定义1:对于无向图G和一棵树T来说,若T中与G中所包含的节点相同,但是边不相同,且T恰好是无环的连通图,那么称T为G的生成树. 对于图的生成 ...

  4. 算法总结——异或运算

    异或运算 总结总结一些算法,也方便自己回顾,定时更新. 运算规则:相同取0,相异取1 异或算法有三个特征: 1.任何数和0做异或运算,结果仍然是原来的数,即a ⊕ 0 = a. 2.任何数和自身做异或 ...

  5. 数据结构与算法:异或运算

    异或: 相同为0,不同为1.(也可以当作"无符号相加") 异或满足交换律. A ^ B ^ C ^ D = D ^ A ^ C ^ B 不用额外变量交换两个数 public sta ...

  6. 【算法】异或 偶数数组中找到一个唯一奇数

    文章目录 1.概述 2.扩展 1.概述 题目如下:已知一个数组中,只有一个数字出现奇数次,其他数字出现偶数次,如何找到这个奇数的数字,而且要求尽量简单,而且时间复杂度为O(n) /*** 测试点: 已 ...

  7. 【数据结构和算法笔记】遍历生成树

    对于非连通图,每个连通分量中的顶点集合遍历走过的边构成一棵生成树,各个连通分量的生成树组成非连通图的生成森林.  

  8. 数据结构及算法之异或

    一.概念 概念来自百度百科. 链接如下: 异或 异或也叫半加运算,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0 ...

  9. 经典算法之异或运算(无进位相加)

    目录 异或运算的定义 异或运算的性质 异或运算的应用 交换两数 翻转指定位 寻找单身狗 异或运算的定义 众所周知,计算机中的所有数据都是以二进制(0或者1)的形式存储.而异或运算符(^)就是将参加运算 ...

  10. 常用CDK生成Java算法(大数异或)

    常用于游戏中的CDK的生成.(如果需求较大,可进一步扩展位数,和一次生成的数量) private static final int mask = 23;//大数异或的标 private static ...

最新文章

  1. 死磕Java并发:J.U.C之阻塞队列:ArrayBlockingQueue
  2. 新松机器人BG总裁高峰_新松与民航物流公司签署战略合作协议
  3. java网络编程之TCP通讯
  4. java swing 图片切换_使用Javaswing自定义图片作为按钮(原创)
  5. mysql日期存到oracle_mysql与oracle的日期/时间函数小结
  6. 404 错误页面_如何设计404错误页面,以使用户留在您的网站上
  7. KindEditor编辑器, 利用ajax动态切换编辑器内容
  8. Sprint2-3.0
  9. 计算机二级矿大考点哪个校区,计算机二级考点哪个近一点555
  10. 尚硅谷设计模式笔记-装饰者模式
  11. 拦截器(Interceptor)和过滤器(Filter)区别
  12. 2022-2027年中国医疗行业市场深度分析及投资战略规划报告
  13. 如何在word中的图片上画圈标注_教你如何轻松在图片上画圈圈、画箭头、写注释...
  14. UA MATH524 复变函数4 复级数与复变函数的积分基础
  15. 接口测试平台代码实现11: 用户管理模块设计和开发
  16. 树的遍历(Java)
  17. Android自定义步骤指示器
  18. 制作单词记录App(一)
  19. PHP为什么只能提交数字到mysql写入_请教高手?php为什么不能把数据写入数据库?...
  20. 全国计算机二级选择题(自总结易错题)

热门文章

  1. maven的pom文件引入依赖报错:提示无法处理 Cannot resolve...
  2. Font Replacer
  3. 百度、太一云、趣链、星合、达令共议什么是真区块链【区块链打假】
  4. scrapy---拉勾网Ajax爬虫
  5. 怎样启动模拟器模拟鸿蒙系统,鸿蒙OS 模拟器运行
  6. 《白夜行》读后感:白夜行走,暗中羁绊
  7. 简析时间复杂度和空间复杂度
  8. ESP32 LVGL8.1 ——msgbox 消息框 (msgbox 28)
  9. python中的Rotation常见报错问题
  10. Integer与Int