图论 学习笔记(提高组)

图的基本概念和数据结构

圆圈表示节点
线是边
图是V和E的二元组

无向图:边没有方向(边是双向的)
有向图:边有方向
无权图:所有边的权重都是1
有权图:权重不同;在不同的应用里,权重的意义不同
没有的边记作0或者无穷大,具体看实际应用
基本原则是进行搜索的时候,使无法通过这条边

数据结构:
无向无权图(Undirected Unweighted Graph)
有向无权图(Dirceted Unwieghted Graph)
无向图的邻接矩阵关于主对角线对称
有向图的邻接矩阵通常是不对称的
有向有权图(Undirected Weighted Graph)


最短路(Shortest Path)
简单路径(Simple Path):路径上没有重复节点即为简单路径
无权图:长度等于边数
有权图:长度等于边权加和
单元最短路(Single-source Shortest Path Problem):
输入图G,起点s
输出到所有点的最短路
无权图最短路算法
int < queue >;
struct a[N]{
int v;//vertex
bool visit = 0;
int dist = inf;
int path = 0;//路径
};
首先把起始点放入队列,设为已访问,距离是0
拿出起始点(dequeue()),如果起始点未被访问过,开始迭代此点;否则取出队列中下一点然后进行相同操作
迭代:
void function()
{
拿出上一点;
visit = 1;
dist[现在点] = dist[上一点] + 1;
path[现在点] = 上一点;
此点插入队列;
return ;
}
由于无向图的最短路仅取决于经过的边数,故越早经过的必然是最短路
if( queue.empty() ) 返回结构体的表;

算法时间复杂度: O(|V|+|E|)
初始化需要把每个点的参量遍历一遍,时间复杂度是O(|V|)
队列操作只会把没有访问过的节点插入,所以每个节点只会被访问一次,时间复杂度是O(|V|);
每个节点只会被访问一次,所以每个边只会被访问一次,时间复杂度是O(|E|)

有权图最短路算法:迪杰斯特拉算法(Dijkstra`s Algorithm)
初始化:
需要一个优先队列(离起始点最近的点在最前面)
以dist为排序依据,同时记录所对应的path(即为指向的点)
一个结构体,包括vertex,dist,path
其中 dist = inf , path = 0;
如果路径更短(dist`=dist+weigth[现在点]),就取代原来的值,并记入path,同时插入到优先队列中
存在自环,所以如果不更新,则不向下迭代;即相等时不更改

tag:SPFA可能还活着


 

最小生成树(Minnimun Spanning Trees)
算法:Prime算法和Kruskal算法

树是一类特殊的无向图(没有回路,是连通图)
Trees are connected acyclic undirected graphs.
树有n个节点,则有n-1条边
少一条边则不再有连通性(disconnected),多一条边则出现回路(cycle)

Spanning Trees(生成树)
保留全部节点,一部分边
输入:一个联通的无向图,有n个点
输出:保留n-1条边
最小生成树:所有生成树中,边权加和最小

Application:Muddy City Problem
·The city has muddy roads.
·The mayor wants to pave roads.
Constraints:
1.Enough road must be paved so that everyone can trave from his house to anyone else`s house.
2.The paving should cost as little as possible.

Prim`s Algorithm(有无权重都可以)
basic idea:Grow the tree in successive stages.
·Initially,the tree has one vertex and no edge.
·In each interation ,add one vertex and one edge to the tree.
·Through,maintain the properties of trees:Connectivity and No cycle
·The algorithm runs in |V| iterations.
步骤:
随便选一个点,加入集合
找起始点连接的最短边(权重最小),将这条边加入集合
再找和这两个点相连的最短边,相邻的点加入集合
(联通点压缩,可以看做一个点)
所有点都在集合里时(即集合中有n个元素)停止运行并输出

Kruskal`s Algorithm:
Basic idea:Maintain a forest,i.e.,a collection if trees.
·Initially,there are n trees;every certex is a tree.
·Each iteration studies one edge; the edge may be chosen so that two trees are merged.
·Stop when there is only one tree.
·The algorithm run in at most |E| iterations.(Because there are |E| edges.)
步骤:
创建一个队列,存储所有的边并按照权重进行升序排列
初始状态下有n棵树
每次操作需要将队列的队首拿出,检查联系的两条边是否联通,如果不连通则加上这条边并记录
如果选中边两端的点已经联通,则拒绝这个边,否则形成回路
由于生成树不多不少需要n-1条边,故从小到大进行选边,正确性得以证明
如何去维护多棵树并判断两棵树是否在同一棵树上以及完成合并操作:并查集 O(1)
时间复杂度:O(m*logm) + m*O(1)
排序:O(mlogm)
循环:每次取出一条边,共O(m)
每次循环需要判断是否属于一个树,有时需要合并两棵树,复杂度都是O(1)

 

posted @ 2023-06-21 14:35  欢黎明陌  阅读(52)  评论(0编辑  收藏  举报