寒假训练 第十二&&十三节 搜索与图论 总结

Dijkstra(迪杰斯特拉)

基本思想

每次新扩展一个距离最短的点,更新与其相邻的点的距离。当所有边权都为正时,由于不会存在一个距离更短的没扩展过的点,所以这个点的距离永远不会再被改变,因而保证了算法的正确性。不过根据这个原理,用Dijkstra求最短路的图不能有负权边,因为扩展到负权边的时候会产生更短的距离,有可能就破坏了已经更新的点距离不会改变的性质。、

特点

优点是方法简单,缺点是效率低。
迪杰斯特拉算法虽然算法简明、能得到最优解,但是效率比较低,运算中占用空间大。

void Dijkstra (int cost [ ][MAX] ,int n,int v){/*迪杰斯特拉算法*/
int dist [MAX] , path [MAX] , s [MAX] ;
int mindis,i,j,u, pre;
for(i=0 ; i<n;i++)
{
	dist [i]=cost[v][i];/*初始化距离*/
	s [ i]=0 ;/*辅助数组s[]置初值为0*/
	if(cost[v] [ i]<M)
		path [ i]=v ;
	else
	path [i]=-1;
	}
s [ v]=1; path[v]=0 ;
for(i=0 ;i<n ;i++){
	mindis=M;
	u=-l;
	for(j=0 ; j<n;j++)
		if(s[j]==0 && dist [j]<mindis)(
			u=j;
			mindis=dist [j];
	if(u ! =-1)
	{
	s [u]=l;
	for (j=0 ;j<n;j++)
		if(s[j]==0)
			if (cost[u][j]<M && dist [u]+cost[u][j]<dist [j]){
			dist [j]=dist [u]+cost[u][j];
			path [j]=u;
			}
	}
}

Floyd算法

基本思想

从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点X到B。所以,我们假设Dis(AB)为节点A到节点B的最短路径的距离,对于每一个节点X,我们检查Dis(AX) + Dis(XB) < Dis(AB)是否成立,如果成立,证明从A到X再到B的路径比A直接到B的路径短,我们便设置Dis(AB) = Dis(AX) + Dis(XB),这样一来,当我们遍历完所有节点X,Dis(AB)中记录的便是A到B的最短路径的距离。

状态转移方程: d[i,j]:=min{d[i,k]+d[k,j],d[i,j]};

void floyd() {
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            d[0][i][j] = graph[i][j];
    for(int k = 1; k <= n; k++) {
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                d[k][i][j] = min(d[k-1][i][j], d[k-1][i][k] + d[k-1][k][j]);
            }
        }
    }
}

bellman-ford

Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(当然也可以是无向图)。

核心三层for玄幻

第一层 k是作为中间顶点
第二层 v是作为起始顶点
第三层 w是作为终点顶点

for (int k = 0; k < graph.getNumVex(); k++)
{
	for (int v = 0; v < graph.getNumVex(); v++)
	{
		for (int w = 0; w < graph.getNumVex(); w++)
		{
			if (d[v][w] > d[v][k] + d[k][w])
			{
				d[v][w] = d[v][k] + d[k][w];
				p[v][w] = p[v][k];// p[v][w]是v--w最短路径上 v的下一顶点
            }
        }
    }
}

SPFA

SPFA算法是求单源最短路径的一种算法,它是Bellman-ford的队列优化,它是一种十分高效的最短路算法。

基本思想

在建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点去刷新起始点到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空。

int spfa_dfs(int u)
{
    vis[u]=1;
    for(int k=f[u]; k!=0; k=e[k].next)
    {
        int v=e[k].v,w=e[k].w;
        if( d[u]+w < d[v] )
        {
            d[v]=d[u]+w;
            if(!vis[v])
            {
                if(spfa_dfs(v))
                    return 1;
            }
            else
                return 1;
        }
    }
    vis[u]=0;
    return 0;

你可能感兴趣的:(算法,深度优先,图论)