#include <iostream> #include <queue> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #define MAXN 150005 const int INF = 9999999; using namespace std; int N, M; struct node{ int to, cost; int next; }; node e[150005]; //e数组读取边的信息 int d[30005], adj[30005]; //d数组表示到原点的最短距离,adj表示某一点最后出现的位置; bool vis[30005]; //访问数组 void spfa() { for (int i = 0; i < 30005; i++) d[i] = INF; d[1] = 0; memset(vis, 0, sizeof(vis)); int sta[30005]; ////栈模拟,等价于用stack<int> int top = 0; vis[1] = 1; sta[++top] = 1; while (top){ int pos = sta[top--]; vis[pos] = 0; for (int i = adj[pos]; i != -1; i = e[i].next){ int to = e[i].to; int cost = e[i].cost; if (d[to] > d[pos] + cost){ d[to] = d[pos] + cost; if (vis[to] == 0){ sta[++top] = to; vis[to] = 1; } } } } return; } int a, b, c; int main() { while (scanf("%d%d", &N, &M) != EOF){ memset(vis,0,sizeof(vis)); for (int i = 0; i < 30005; i ++) adj[i] = -1; //默认adj[i] = -1 时再往上找无边 //多组数据必要的清空 for (int i = 0; i < M; i++){ scanf("%d%d%d", &a, &b, &c); e[i].to = b; e[i].cost = c; e[i].next = adj[a]; //next记录下上一次从a出发在e[i]中的位置 adj[a] = i; //记录下出发点a最后一次出现的位置 } spfa(); printf("%d\n", d[N]); } }
#include <iostream> #include <queue> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #define INF 0x3f3f3f3f #define MAXN 1000005 using namespace std; int N, M; struct node{ int to, cost; }; vector <node> e[30005]; int d[30005]; bool vis[30005]; int cmp(int a, int b){return a > b;} void spfa() { for (int i = 0; i < 30005; i++) d[i] = INF; d[0] = 0; d[1] = 0; memset(vis, 0, sizeof(vis)); queue<int> q; vis[1] = 1; q.push(1); while (!q.empty()){ int tmp = q.front(); q.pop(); vis[tmp] = 0; for (int i = 0; i < e[tmp].size(); i++){ node cur = e[tmp][i]; if (d[cur.to] > d[tmp] + cur.cost){ d[cur.to] = d[tmp] + cur.cost; if (vis[cur.to] == 0){ q.push(cur.to); vis[cur.to] = 1; } } } } return; } int a, b, c; node input; int main() { while (scanf("%d%d", &N, &M) != EOF){ memset(vis,0,sizeof(vis)); for (int i = 0; i < M; i++){ scanf("%d%d%d", &a, &b, &c); input.to = b; input.cost = c; e[a].push_back(input); //存放到vector中 } spfa(); sort(d, d+N+1, cmp); printf("%d\n", d[0]); } }
#include <stdio.h> //定义输入/输出函数 #include <limits.h> //定义各种数据类型最值常量 #include <math.h> //定义数学函数 #include <stdlib.h> //定义杂项函数及内存分配函数 #include <string.h> //字符串处理 #include <algorithm>//算法 #include <queue>//队列 #include <stack>//栈 using namespace std; int N, M; int re[1005]; //源根 int finds(int x){ //找根函数 if (re[x] == x) return x; else return re[x] = finds(re[x]); } struct node{ int from, to, cost; }; node a[20005]; int vis[1005]; int cmp(node a, node b){return a.cost > b.cost;} long long sum; int flag; int main() { while (scanf("%d%d", &N, &M) != EOF){ for (int i = 0; i < M; i++) scanf("%d%d%d", &a[i].from, &a[i].to, &a[i].cost); sort(a, a+M, cmp); //读取输入 for (int i = 0; i <= N; i++) re[i] = i; //根重置 memset(vis, 0, sizeof(vis)); //访问重置 sum = flag = 0; for (int i = 0; i < M; i++){ if (finds(a[i].from) == finds(a[i].to)) continue; //如果查找后两数根不相等,则进行以下程序 re[finds(a[i].from)] = finds(a[i].to); //直接把一根连在另一根的生成树上 vis[a[i].from] = 1; vis[a[i].to] = 1; sum += a[i].cost; } for (int i = 1; i <= N; i++){ if (vis[i] == 0) flag = 1; if (finds(i) != finds(1)) flag = 1; } if (flag == 1) printf("-1\n"); else printf("%lld\n", sum); } }
#include <stdio.h> //定义输入/输出函数 #include <limits.h> //定义各种数据类型最值常量 #include <math.h> //定义数学函数 #include <stdlib.h> //定义杂项函数及内存分配函数 #include <string.h> //字符串处理 #include <algorithm>//算法 #include <queue>//队列 #include <stack>//栈 #include <vector>//动态数组 using namespace std; int T, N, pos, mins; int map[505][505]; bool vis[505]; int low[505]; int cmp(int a, int b) {return a > b;} int main() { while (scanf("%d", &T) != EOF){ while (T--){ memset(map, 0, sizeof(map)); memset(low, 0, sizeof(low)); memset(vis, 0, sizeof(vis)); scanf("%d", &N); printf("N = %d\n", N); for (int i = 1; i <= N; i++) for (int j = 1; j <= N; j++) scanf("%d", &map[i][j]); for (int i = 1; i <= N; i++) low[i] = map[1][i]; low[1] = 0; vis[1] = pos = 1; for (int i = 1; i < N; i++){ mins = 65550; for (int j = 1; j <= N; j++) if (vis[j] == 0 && mins > low[j]){ mins = low[j]; pos = j; } //在d[N]中找到最小值的位置 vis[pos] = 1; for (int j = 1; j <= N; j++){ if(low[j] > map[pos][j] && vis[j] == 0) low[j] = map[pos][j]; } //用最小值的位置更新Low数组 } //for (int i = 0; i <= N; i++) printf(" %d", low[i]); //printf("\n"); sort(low, low + N + 1, cmp); for (int i = 0; i <= N; i++) printf(" %d", low[i]); printf("\n"); printf("%d\n", low[0]); } } }
给定图G(V, E)(其中V、E分别为图G的顶点集与边集),源点s,数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为, Distant[s]为0;
以下操作循环执行至多n-1次,n为顶点数:
对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;
若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;
为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) < Distant[v]的边,则图中存在负环路,即是说改图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。
可知,Bellman-Ford算法寻找单源最短路径的时间复杂度为O(V*E).
②算法流程:
第一,初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
第二,进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
第三,遍历途中所有的边(edge(u,v)),判断是否存在这样情况:d(v) > d (u) + w(u,v)
存在则赋值;
③算法图示:
#include <stdio.h> //定义输入/输出函数 #include <limits.h> //定义各种数据类型最值常量 #include <math.h> //定义数学函数 #include <stdlib.h> //定义杂项函数及内存分配函数 #include <string.h> //字符串处理 #include <algorithm>//算法 #include <queue>//队列 #include <stack>//栈 const int INF = 0x3f3f3f3f; using namespace std; struct node{ int to, cost; int next; }; node e[2][1000005]; int N, P, Q; int adj[2][1000005], d[1000005]; bool vis[1000005]; int a, b, c; long long sum; void spfa(int k) { memset(vis, 0, sizeof(vis)); memset(d, INF, sizeof(d)); stack <int> s; //开queue 也行,一样时间与内存 s.push(1); d[1] = 0; vis[1] = 1; while (!s.empty()){ int pos = s.top(); s.pop(); vis[pos] = 0; for (int i = adj[k][pos]; i!= -1; i = e[k][i].next){ int to = e[k][i].to; int cost = e[k][i].cost; if (d[to] > d[pos] + cost){ d[to] = d[pos] + cost; if (vis[to] == 0){ s.push(to); vis[to] = 1; } } } } } int main() { while (scanf("%d", &N) != EOF){ while (N--){ memset(adj, -1, sizeof(adj)); memset(e, 0, sizeof(e)); sum = 0; scanf("%d%d", &P, &Q); for (int i = 0; i < Q; i++){ scanf("%d%d%d", &a, &b, &c); e[0][i].to = b; e[0][i].cost = c; e[0][i].next = adj[0][a]; adj[0][a] = i; e[1][i].to = a; e[1][i].cost = c; e[1][i].next = adj[1][b]; adj[1][b] = i; } spfa(0); for (int i = 1; i <= P; i++) sum += d[i]; //printf("\n"); spfa(1); for (int i = 1; i <= P; i++) sum += d[i]; //printf("\n"); printf("%lld\n", sum); } } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
整合:图论存图方法及三种重要做法分析(Kruskal Dijkstra Bellman-Ford)
原文:http://blog.csdn.net/greedwish_x/article/details/47169673