三月算法学习总结
2020-3-23
一:图论基本算法:
小提纲:
几个概念:
度数:无向图中一个点连出去的边数
联通:两个点通过路径相连
拓扑图:没有环的图、
三无图:无向,无重边,无自环
割点:删除这个点之后图不连通
桥边: 删除这个边之后图不连通
强联通:有向图中,两个点可以互相到达
强联通分量( SCC):有向图中,分量中所有点可以互相到达
点双联通分量:没有割点;
边双联通分量:没有割边;
几个结论:
1.一个图里的树边必然是n-1
2.二分图里:
*1.1 最短路总结(较重要):**
其实bfs解决最短路是没问题的,感觉bfs启发了最短路算法。
算法 | 数据规模 | 复杂度 | 数据结构 | 边权 | 用法 |
---|---|---|---|---|---|
floyd | 200 | O(n^3) | 邻接矩阵 | 有负 | 解决一些其他问题挺方便 |
spfa | >=1e7 | O(n*m) | 邻接表,前向星 | 有负 | 随机数据线性时间,网格图可以拉满复杂度,可判负边,比较好写 |
dijkstra | >=1e7 | O(m*log(n)) | 邻接表,前向星 | 无负 | 较快通用算法 |
floyd求传递闭包:
听着挺牛逼的概念,其实挺简单的东西,a和d没有直连边,但a通过b,c又可以走到d,所以a可以走到d。
例:zoj-4124;求闭包传递。
1.2 差分约束:
解决一系列线性规划问题:
把x1,x2,等等,看做最短路节点,
跑一遍spfa,对于每一条边起点u,终点v,都有:
那么在求解最短路的时候,实际上是得到一组最大解(因为 若干个 = 的成立)。
求解最长路,得到的是一组最小解。
板题:poj3159
跑一遍spfa,前向星+模拟队列,不然TLE
1.3 拓扑图
做法:
按顺序跑一遍,可以bfs,dfs,个人喜欢bfs。
做法:找出入度为0的点,开始广搜。
用法:
-
判断有没有环:拓扑时记录出队人数,小于n必有环。
-
当拓扑队列里人数超过2时,说明有排名并列。
例题:
T123571 Misaka Network
按拓扑序选择,
记得当时犯了一个逻辑错误:一个点不是控制点,就是如果有控制点连到它就行了。
但,一个点是控制点,不是说连到它的点不是控制点就行了,只要有一个连到它的控制点,那它就不是控制点。
1.4 欧拉路(一笔画)
做法:
无向图:
第一步:判断是否联通,并查集解决;
第二步:
有向图:
第一步:判断是否联通,并查集解决;
第二步:记录出入度数
例题:
B - Grid with Arrows
网格图欧拉路,开不了数组,蛋疼的动态过不了,哈希处理
1.5 无向图求割点及割边
tarjan算法:
一张图搞成一颗dfs树;
low数组表示可到达祖先,dep表示递归深度;
如果 low[v]>=num[u],说明是割点;
如果 low[v]>num[u] 说明是割边;
如果 num[v]<num[u]&&v!=fa,说明是回退边,
求构成边连通分量的最小边:
运用缩点技术:
在dfs的时候,low值相同的点必然在一个边双联通分量里,把每一个双连通分量压缩成为一个点求解。
1.6 有向图求强联通分量
还是tarjan算法
有以下结论:
1.一个强联通分量的所有的可以互相访问,low值相同。
2.用栈保存节点(注意是边,而不是点),dfs撞到 low=dep的点 ,把栈里元素全抖出来,构成一个SCC。
1.7 最小生成树
贪心取边+并查集联通(较简单)复杂度(O(E log(E)+E))
1.8 二分图匹配(较重要)
如图:一个图分成了两个部分,这两个独立集内部都没有边,这就是一个二分图。
几个结论:
如何判断一个图可以搞成二分图?
采用染色法,每两个相邻的点必然不在一个独立集里,把他们染成不同的颜色。
二分图等价于没有奇环的图
如果有奇环,染色染出来必然矛盾。
二分图匹配(匈牙利算法)
较简单,
点u,v可以匹配,当且仅当 u,v都还未匹配,或者u已经匹配的点可以换人匹配,最终使得u,v匹配。
写法:
bool findpath(int u){
for(int i=0;i<e[u].size();i++){
int v=e[u][i];
if(!vis[v]){
vis[v]=1;
if(!match[v]||findpath(match[v])){
match[v]=u;
return 1;
}
}
}
return 0;
}