第十一章 图论相关知识点总结

图论知识点

1、表达式树

2、最小生成树

G=(V,E),连接图G的所有点,且边集是E是子集的树称为G的生成树,而权值最小的生成树称为最小生成树。构造最小生成树,可以采用Kruskal算法。

一、Kruskal算法(求图中最小生成树算法)

Kruskal算法首先将按照边的权值,将各边按照从小到大的顺序排列,然后依次考察各边(u,v)。

情况1:u和v在同一连通分量中,那么假如(u,v)后会形成环(即首尾相连),因此不能选择。

情况2:如果u和v在不同的连通分量里,那么加入(u,v)一定是最优的。

//n个顶点,m条边,u[i],v[i]表示第i条边的两个端点,w[i]表示第i条边的权值
//排序后第i小的边的序号保存在r[i]中。 
int cmp(const int i,const int j){return w[i]


二、Dijkstra算法(求图中单源最短路)

Dijkstra算法用于求解边权为正,从单个源点出发,到所有结点的最短路。该算法同时适用于有向图和无向图。

假设起点是结点 0,它到结点i的路径长度为d[i].未标号结点的v[i]=0,已标号结点的v[i]=1。为了简单起见,用w[x][y]=INF表示边(x,y)不存在。

memset(v,0,sizof(v));
//设置d[0]=0,其余为INF. 
for(int i=0;i

打印路径的时候,从终点出发,不断顺着d[i]+w[i][j]==d[j]边回退到起点,也可以在进行算法中,记录最短路径的父节点。


邻接表存储图

使用邻接表存储图,在稀疏的图中有空间优势。下面的代码分别采用数组和vector的方式实现邻接表建图。

//首先需要给每条边编号,first[u]保存结点u的第一条边的编号,
//next[e]表示编号为e的边的“下一条边”的编号。
//下面是使用数组建立邻接表的过程。
int n,m
int first[manx];
int u[maxm],v[maxm],w[maxm],next[maxm];
void read_graph()
{
	scanf("%d%d",&n,&m);//输出顶点数量和边的数量 
	for(int i=0;i
版本二:采用结构题和优先队列实现Dijkstra算法
struct Edge 
{
	int from, to, dist;
	Edge(int u,int v,int d):from(u),to(v),dist(d){}
}; 
struct Dijkstra 
{
	int n,m;
	vector edges;
	vector G[maxn];
	bool done[maxn];//是否进行标记 
	int d[maxn];//s到各点的距离 
	int p[maxn];//最短路中的上一条边
	
	void init (int n)
	{
		this->n = n;
		for(int i=0;i Q;
	for(int i=0;id[u]+e.dist)
			{
				d[e.to] = d[u] + e.dist;
				p[e.to] = G[u][i];
				Q.push((HeapNode){d[e.to],e.to});
				//使用优先队列进行动态排序。 
			}
		}
	} 
}

三、Bellman-Ford 算法(图中有负权,当最短路存在时,求最短路)

代码如下:

for (int i=0;i

采用队列形式实现代码:

bool bellman_ford(int s)
{
	queue Q;
	memset(inq,0,sizeof(inq));
	memset(cnt,0,sizeof(cnt));
	for(int i=0;i d[u] + e.dist)
			{
				e[e.to] = d[u] + e.dist;
				p[e.to] = G[u][i];
				if(!inq[e.to])
				{
					Q.push(e.to);
					inq[e.to]= true;
					if(++cnt[e.to]>n)
						return false;
				}
			}
		}
	}
	return true;
}


三、Floyd算法(求图中每两点的距离)

初始时,d[i][i]=0,其他d值设置为无穷大。

for(int k=0;k


通过将代码中最后一行更换成d[i][j] = d[i][j] || (d[i][k] && d[k][j])

你可能感兴趣的:(算法竞赛)