一、无根树转化为有根树
1.1 用vector<>数组存储,见ny_20吝啬的国度(用到dfs深搜,转化为以 s 为根结点的树)
void dfs(int x){ int i; for(i=0;i<a[x].size();i++){ if(pre[a[x][i]])//如果父节点已经存在 continue;//跳过 pre[a[x][i]]=x;//否则 x为a[x][i]的父节点 dfs(a[x][i]);//继续搜索与a[x][i]相连结点情况 } }
二、最小生成树
2.1最小生成树的概念
生成树(Spanning Tree):在无向图中,连通且不含圈的图为树(Tree)。给定无向图G=(V,E),连接G中所有点,且边集是E的子集的树称为G的生成树。权值最小的生成树称为最小生成树(Minimal Spanning Tree,MST)。构造最小生成树常见算法:Kruskal 算法(易编写)和 Prim 算法。
2.2 Kruskal算法
1、算法思想:所有边从小到大依次排序(sort、qsort);依次考查每条边(u,v),有两种情况:
情况1:u和v在同一个连通分量中,那么加入(u,v)后会形成环,因此不能选。
情况2:如果不在一个连通分量,那么加入(u,v)一定是最优解,证明反证法:不加(u,v)存在最小生成树的话,那么加 上(u,v)一定有且只有一个环,环中至少有一条边(u’,v’)的权值大于(u,v)的权值。那么删除该边后,得到的新树T’=T+(u,v)-(u’,v’)<= T。所以(u,v)是最优解。(很绕可以略过证明)
?问题1—— 判断任意两个点是否在同一个连通分量,还需要合并两个连通分量。
办法1:暴力 (dfs,bfs),算法效率低
办法2:并查集(Union-Find Set)
并查集的递归思想:把 X 的父节点保存在P[X]中(如果x没有父节点,则P[X])
弊端:假如这棵树是长长的一条链,每次查找就会很慢。优化:可以用压缩路径来优化。
2 模板《Kruskal》。例题:hdu_1863 畅通工程
2.3Prim算法
1 基本思想:以顶点为主导地位,从起始顶点出发,通过选择当前可用的最小权值边依次把其他顶点加入到生成树当中来。
2 模板 《Prim》。 例题:xynu_1392 最优布线问题