图论——最短路算法

单源最短路

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 }

 

posted @ 2018-08-25 22:10  Rogn  阅读(498)  评论(0编辑  收藏  举报