基础图论知识总结

Posted 77458

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基础图论知识总结相关的知识,希望对你有一定的参考价值。

1.  最短路

何为最短路?

给定两个顶点,在以这两个点为起点和终点的路径中,边的权值和最小的路径即为最短路

何为单源最短路?何为两点之间的最短路?

固定一个起点,求它到其他所有点的最短路的问题,终点也固定的问题叫做两点之间的最短路问题

BellmanFord  算法

记从起点 S  出发到顶点i 的最短路径为 d[i]  ,则存在下述等式

d[i]=mind[j]+cost(i,j)|e=(i,j)E 
其中 cost(i,j)  表示路径 e(i,j)  的花费

对于给定的初始化起点 S  ,我们设初值d[S]=0,d[i]=INF ,然后不断更新 d  的值即可求出最终的答案

时间复杂度为O(|V|×|E|) 


const int INF = 0x3f3f3f3f;
const int MAXN = 1e3 + 5;
struct edge
    int from, to, cost;


edge es[MAXN];//边

int d[MAXN];//最短距离

int V, E;//V是顶点数,E是边数

//求解顶点s到所有点的最短距离

void shortest_path(int s)
    memset(d, 0x3f, sizeof(d));
    d[s] = 0;//初始位置最短距离即为0
    while(true)
        bool update = false;
        for(int i = 0;i < E;i ++)
            edge e = es[i];
            if(d[e.from] != INF && d[e.to] > d[e.from] + e.cost)
                d[e.to] = d[e.from] + e.cost;
                update = true;
            
        
        if(!update) break;
    

如果要检查负环,则要对 d[i]  初始化为 0  ,可以检查出所有的负环

时间复杂度为O(|V|×|E|) 

//返回true则存在负环

bool find_negative_loop()
    memset(d, 0, sizeof(d));

    for(int i = 0;i < V;i ++)
        for(int j = 0;j < E;j ++)
            edge e = es[j];
            if(d[e.to] > d[e.from] + e.cost)
                d[e.to] = d[e.from] + e.cost;

                //如果第n次仍然更新了,则存在负环
                if(i == V - 1) return true;
            
        
    
    return false;

Dijkstra  算法

基于 BellmanFord  算法进行优化,做如下修改:

  1. 找到最短距离已经确定的顶点,从它出发更新相邻顶点的最短距离

  2. 此后不需要关系 1  中”最短距离已经确定的顶点”

用邻接矩阵实现的Dijkstra 算法的复杂度是 O(|V| 2 )  ,如下是使用优先队列进行优化的代码
时间复杂度为 O(|E|×log|V|) 

const int MAXN = 1e3 + 5;
const int INF = 0x3f3f3f3f;
struct edge
    int to, cost;


typedef pair<int, int >PII;//first是最短距离,second是顶点的编号

int V;
vector<edge>G[MAXN];
int d[MAXN];

void dijkstra(int s)

    //通过制定greater<PII>参数,堆按照first从小到大的顺序取出值
    priority_queue<PII, vector<PII>, greater<PII> >que;
    memset(d, 0x3f, sizeof(d));
    d[s] = 0;
    que.push(PII(0, s));

    while(!que.empty())
        PII e = que.top();
        que.pop();
        int v = e.second;
        if(d[v] < e.first) continue;//如果取出的不是最短距离则继续取
        for(int i = 0;i < G[v].size();i ++)
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.cost)
                d[e.to] = d[v] + e.cost;
                que.push(PII(d[e.to], e.to));
            
        
    

如果存在负边,则还需使用 BellmanFord  算法

FloydWarshall  算法

作用:任意两点之间的最短路问题

列出状态转移方程:

d[i][j]=min(d[i][j],d[i][k]+d[k][j]) 
可以处理负数即负边,而判断图中是否有负环,只需检查是否存在 d[i][i]  是负数的顶点 i  就可以了

int d[MAXN][MAXN];//d[v][u]表示边e=(u,v)的权值(不存在时舍为INF, 不过d[i][i]=0)
int V;//顶点数

void warshall_floyd()
    for(int k = 0;k < V;k ++)
        for(int i = 0;i < V;i ++)
            for(int j = 0;j < V;j ++)
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            
        
    

路径还原

在求解最短距离时,满足d[j]=d[k]+cost[k][j] 的顶点 k  ,就是最短路上顶点基础图论知识总结

基础图论知识总结

专题四-图论总结

专题四-图论总结

图论的小总结

图论问题复习总结