zoukankan      html  css  js  c++  java
  • 图论——最短路算法

    单源最短路

    Dijkstra + 邻接矩阵

    O(V2 + E)

     1 const int maxn = 1000;    //顶点最大数
     2 int edge[maxn][maxn];    //存图
     3 int dis[maxn];            //源到各顶点的最短距离
     4 int vis[maxn];            //记录是否被访问,用来代替集合S
     5 
     6 //s为起点,n为总节点数
     7 void Dijsktra(int s, int n)
     8 {
     9     memset(vis, false, sizeof(vis));
    10     vis[s] = true;
    11     for (int i = 1;i <= n; i++)
    12         dis[i] = edge[s][i];
    13     dis[s] = 0;
    14 
    15     //总共进行n次循环
    16     for (int i = 1; i <= n - 1; i++)
    17     {
    18         int u = -1, mi = INF;
    19         for (int j = 1;j <= n; j++)
    20         {
    21             if (!vis[j] && dis[j] < mi)
    22             {
    23                 mi = dis[u = j];
    24             }
    25         }
    26 
    27         vis[u] = true;
    28 
    29         //松弛与u相连的边
    30         for (int j = 1; j <= n; j++)
    31             if (!vis[j])
    32                 dis[j] = min(dis[j], dis[u] + edge[u][j]);
    33     }
    34 }

    Dijkstra + STL priority_queue + 链式前向星

    O((V + E)lgV)

     1 const int maxv = 1000;    //最大顶点数
     2 const int maxe = 10000;    //最大边数
     3 int dis[maxv];            //源到各顶点的最短距离
     4 int vis[maxv];            //记录是否被收录,用来代替集合S
     5 int head[maxv];            //采用链式前向星建图
     6 struct Node
     7 {
     8     int u, d;            //该节点的编号与距离
     9     bool operator < (const Node x) const
    10     {
    11         return  d > x.d;
    12     }
    13 };
    14 
    15 struct Edge
    16 {
    17     int to, w, next;
    18 }edge[maxe];
    19 
    20 
    21 inline void addedge(int u, int v, int w,int id)
    22 {
    23     edge[id].to = v;
    24     edge[id].w = w;
    25     edge[id].next = head[u];
    26     head[u] = id;
    27 }
    28 //s为起点
    29 void Dijsktra(int s)
    30 {
    31     priority_queue<Node>q;            //取出集合T中的最小值
    32     memset(vis, 0, sizeof(vis));
    33     memset(dis, INF, sizeof(dis));    //与邻接矩阵不同,这里初始化为INF就可以,原因自己想
    34 
    35     dis[s] = 0;
    36     q.push(Node{ s, dis[s] });
    37     while (!q.empty())
    38     {
    39         Node x = q.top(); q.pop();
    40         int u = x.u;
    41 
    42         if (vis[u])    continue;
    43 
    44         vis[u] = true;
    45         for (int i = head[u]; i != -1; i = edge[i].next)    //松弛与u直接相邻的顶点
    46         {
    47             int v = edge[i].to;
    48             int w = edge[i].w;
    49             if (!vis[v] && dis[u] + w < dis[v])
    50             {
    51                 dis[v] = dis[u] + w;
    52                 q.push(Node{ v,dis[v] });
    53             }
    54         }
    55     }
    56 }

    Dijkstra + STL priority_queue + 邻接表

    O((V + E)lgV)

     1 const int maxv = 1000;    //最大顶点数
     2 int dis[maxv];            //源到各顶点的最短距离
     3 int vis[maxv];            //记录是否被收录,用来代替集合S
     4 struct Node
     5 {
     6     int u, d;            //该节点的编号与距离
     7     bool operator < (const Node x) const
     8     {
     9         return  d > x.d;
    10     }
    11 };
    12 vector<Node>G[maxv];
    13 
    14 //s为起点
    15 void Dijsktra(int s)
    16 {
    17     priority_queue<Node>q;            //取出集合T中的最小值
    18     memset(vis, 0, sizeof(vis));
    19     memset(dis, INF, sizeof(dis));    //与邻接矩阵不同,这里初始化为INF就可以,原因自己想
    20     dis[s] = 0;
    21     q.push(Node{ s, dis[s] });
    22     while (!q.empty())
    23     {
    24         Node x = q.top(); q.pop();
    25         int u = x.u;
    26 
    27         if (vis[u])    continue;
    28 
    29         vis[u] = true;
    30         for (int i = 0; i < (int)G[u].size(); i++)    //松弛与u直接相邻的顶点
    31         {
    32             int v = G[u][i].u;
    33             int w = G[u][i].d;
    34             if (!vis[v] && dis[u] + w < dis[v])
    35             {
    36                 dis[v] = dis[u] + w;
    37                 q.push(Node{ v,dis[v] });
    38             }
    39         }
    40     }
    41 }

    Bellman-Ford

    O(VE)

     1 const int maxv = 1000;            //最大顶点数
     2 const int maxe = 10000;            //最大边数
     3 int dis[maxv];
     4 struct Edge
     5 {
     6     int u, v, w;
     7 }edge[maxe];
     8 int n, m;
     9 
    10 bool Bellman_Ford(int s)
    11 {
    12     memset(dis, INF, sizeof(dis));
    13     dis[s] = 0;
    14     for (int k = 1; k <= n - 1; k++)
    15         for (int i = 0; i < m; i++)
    16         {
    17             int u = edge[i].u, v = edge[i].v, w = edge[i].w;
    18             if (dis[u] + w < dis[v])  dis[v] = dis[u] + w;
    19         }
    20 
    21     for (int i = 0; i < m; i++)
    22         if (dis[edge[i].v] > dis[edge[i].u] + edge[i].w)
    23             return false;
    24     return true;
    25 }

    SPFA(Short Path Faster Algriothm)+链式前向星

    O(kE) (k<2)

     1 bool SPFA(int s)
     2 {
     3     queue<int>q;
     4     memset(inq, false, sizeof(inq));
     5     memset(cnt, 0, sizeof(cnt));
     6     for (int i = 1; i <= n; i++)  dis[i] = INF;
     7     dis[s] = 0;
     8     inq[s] = true;
     9     q.push(s);
    10 
    11     while (!q.empty())
    12     {
    13         int u = q.front(); q.pop();
    14         inq[u] = false;
    15         for (int i = head[u]; i != -1; i = edge[i].next)
    16         {
    17             int v = edge[i].to, w = edge[i].w;
    18             if (dis[v] > dis[u] + w)
    19             {
    20                 dis[v] = dis[u] + w;
    21                 if (!inq[v])
    22                 {
    23                     inq[v] = true;
    24                     q.push(v);
    25                     if (++cnt[v] > n)  return false;
    26                 }
    27             }
    28         }
    29     }
    30     return true;
    31 }

    SPFA+SLF优化

     1 const int maxv = 1000;        //最大顶点数
     2 const int maxe = 10000;        //最大边数
     3 int dis[maxv], cnt[maxv];
     4 bool inq[maxv];                //记录是否在队中
     5 int head[maxv];
     6 int n, m;
     7 
     8 struct Edge
     9 {
    10     int to, w, next;
    11 }edge[maxe];
    12 
    13 inline void addedge(int u, int v, int w, int id)
    14 {
    15     edge[id].to = v;
    16     edge[id].w = w;
    17     edge[id].next = head[u];
    18     head[u] = id;
    19 }
    20 
    21 bool SPFA(int s)
    22 {
    23     deque<int>q;
    24     memset(inq, false, sizeof(inq));
    25     memset(cnt, 0, sizeof(cnt));
    26     for (int i = 1; i <= n; i++)  dis[i] = INF;
    27     dis[s] = 0;
    28     inq[s] = true;
    29     q.push_back(s);
    30 
    31     while (!q.empty())
    32     {
    33         int u = q.front(); q.pop_front();
    34         inq[u] = false;
    35         for (int i = head[u]; i != -1; i = edge[i].next)
    36         {
    37             int v = edge[i].to, w = edge[i].w;
    38             if (dis[v] > dis[u] + w)
    39             {
    40                 dis[v] = dis[u] + w;
    41                 if (!inq[v])
    42                 {
    43                     inq[v] = true;
    44                     //SLF优化
    45                     q.push_back(v);
    46                     if (++cnt[v] > n)  return false;
    47                     if (dis[q.back()] < dis[q.front()])
    48                     {
    49                         int k = q.back();
    50                         q.pop_back();
    51                         q.push_front(k);
    52                     }
    53                 }
    54             }
    55         }
    56     }
    57     return true;
    58 }

    SPFA+LLL优化

     1 const int maxv = 1000;        //最大顶点数
     2 const int maxe = 10000;        //最大边数
     3 int dis[maxv], cnt[maxv];
     4 bool inq[maxv];                //记录是否在队中
     5 int head[maxv];
     6 int n, m;
     7 
     8 struct Edge
     9 {
    10     int to, w, next;
    11 }edge[maxe];
    12 
    13 inline void addedge(int u, int v, int w, int id)
    14 {
    15     edge[id].to = v;
    16     edge[id].w = w;
    17     edge[id].next = head[u];
    18     head[u] = id;
    19 }
    20 
    21 bool SPFA(int s)
    22 {
    23     deque<int>q;
    24     memset(inq, false, sizeof(inq));
    25     memset(cnt, 0, sizeof(cnt));
    26     for (int i = 1; i <= n; i++)  dis[i] = INF;
    27     dis[s] = 0;
    28     inq[s] = true;
    29     q.push_back(s);
    30 
    31     while (!q.empty())
    32     {
    33         int sum = 0, num = 0;
    34         int u = q.front(); q.pop_front();
    35         sum += dis[u];
    36         num++;
    37         inq[u] = false;
    38         for (int i = head[u]; i != -1; i = edge[i].next)
    39         {
    40             int v = edge[i].to, w = edge[i].w;
    41             if (dis[v] > dis[u] + w)
    42             {
    43                 dis[v] = dis[u] + w;
    44                 if (!inq[v])
    45                 {
    46                     inq[v] = true;
    47                     q.push_front(v);
    48                     //LLL优化
    49                     sum += v; num++;
    50                     if (++cnt[v] > n)  return false;
    51                     while (dis[q.front()] < (sum * 1.0 / num))
    52                     {
    53                         int k = q.front(); q.pop_front();
    54                         q.push_back(k);
    55                     }
    56                 }
    57             }
    58         }
    59     }
    60     return true;
    61 }

    SPFA + dfs优化

    O(VlongV) ?

     1 const int maxv = 1000;        //最大顶点数
     2 const int maxe = 10000;        //最大边数
     3 int dis[maxv], cnt[maxv];
     4 bool inStack[maxv];            //记录是否在栈中
     5 int head[maxv];
     6 int n, m,s;                    //s记录源点
     7 bool flag = false;            //记录是否存在负环
     8 
     9 struct Edge
    10 {
    11     int to, w, next;
    12 }edge[maxe];
    13 
    14 inline void addedge(int u, int v, int w, int id)
    15 {
    16     edge[id].to = v;
    17     edge[id].w = w;
    18     edge[id].next = head[u];
    19     head[u] = id;
    20 }
    21 
    22 void init()
    23 {
    24     memset(inStack, 0, sizeof(inStack));
    25     memset(cnt, 0, sizeof(cnt));
    26     for (int i = 1; i <= n; i++)  dis[i] = INF;
    27     dis[s] = 0;
    28 }
    29 void SPFA_DFS(int u)
    30 {
    31     inStack[u] = true;
    32     for (int i = head[u]; i != -1; i = edge[i].next)
    33     {
    34         int v = edge[i].to, w = edge[i].w;
    35         if (dis[v] > dis[u] + w)
    36         {
    37             //dfs一个点,如果从它dfs出去的点能够返回来更新它的话,说明构成了负环
    38             if (inStack[v]) { flag = true; return; }
    39             dis[v] = dis[u] + w;
    40             SPFA_DFS(v);
    41             if (flag)  return;
    42         }
    43     }
    44     inStack[u] = false;
    45 }

     Floyd-Warshall

    O(V3)

     1 const int maxv = 1000;        //最大顶点数
     2 const int maxe = 10000;        //最大边数
     3 int n, m;
     4 int dis[maxv][maxv];
     5 int maze[maxv][maxv];
     6 
     7 void Floyd()
     8 {
     9     for (int i = 1; i <= n; i++)
    10         for (int j = 1; j <= n; j++)
    11             dis[i][j] = (i == j ? 0 : maze[i][j]);    //这样写要在输入前将maze初始化为无穷大
    12 
    13     for (int k = 1; k <= n; k++)            //k必须在最外层,i,j可以交换
    14         for (int i = 1; i <= n; i++)
    15             for (int j = 1; j <= n; j++)
    16                 dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    17 }
  • 相关阅读:
    [ 低危 ] mt网CRLF
    mysql之字段的修改,添加、删除,多表关系(外键),单表详细操作(增删改)
    mysql 之编码配置、引擎介绍、字段操作、数据类型及约束条件
    Navicat Premium永久激活方式
    centos 用户名密码忘记了怎么办?
    并发编程总结
    初识mysql
    线程queue、线程进程池,协程
    python解释器
    线程全局修改、死锁、递归锁、信号量、GIL以及多进程和多线程的比较
  • 原文地址:https://www.cnblogs.com/lfri/p/9516450.html
Copyright © 2011-2022 走看看