图论——最短路算法
单源最短路
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 }
个性签名:时间会解决一切