标签:event 选择 const 需要 bit queue floyd 节点 tor
Floyd()
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N = ???; 5 const int INF = 0x3f3f3f3f; 6 int n, m; 7 int a, b, x; 8 int dis[N][N]; 9 10 void Floyd(){ 11 for(int k=0; k<n; k++) 12 for(int i=0; i<n; i++) 13 for(int j=0; j<n; j++) 14 //选择从i到j的最短路 ( 比较当前知道的i到j的最短距离 与 从i到k再到j的距离) 15 if(dis[i][j] < dis[i][k]+dis[k][j]) 16 dis[i][j] = dis[i][k] + dis[k][j]; 17 //dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);min比较慢 18 } 19 20 int main() 21 { 22 while(scanf("%d %d",&n,&m)!=EOF){ 23 //初始化 24 for(int i=0; i<n; i++){ 25 for(int j=0; j<n; j++) 26 dis[i][j] = INF; 27 dis[i][j] = 0; 28 } 29 //输入两点距离 30 for(int i=0; i<m; i++){ 31 scanf("%d %d %d", &a, &b, &x); 32 x = min(dis[a][b], x); 33 dis[a][b] = dis[b][a] = x; 34 } 35 // 36 Floyd(); 37 // 38 int S,T; 39 scanf("%d %d",&S,&T); 40 if(dis[S][T]==INF) printf("-1\n"); 41 else printf("%d\n",dis[S][T]); 42 } 43 44 }
Bellman()
1 #include<iostream> 2 #include<algorithm> 3 #include<bits/stdc++.h> 4 using namespace std; 5 6 const int inf = 0x3f3f3f3f; 7 const int num = ??? 8 struct edge{int u, v, w;}e[???];//边:起点u,终点v,权值(距离)w 9 int n, m, cnt; 10 int dis[num];//从规定的起点到一点的距离 11 int pre[num];//记录前驱节点 12 //eg:pre[x] = y,指从规定的起点到x点的最短路径为 起点->y->x 13 14 //打印从s到t的最短路径 15 void print_path(int s, int t){ 16 if(s == t) {printf("%d\n",s); return;} 17 print_path(s, pre[t]); 18 printf("->%d",t); 19 } 20 21 // 22 void bellman(){ 23 int s = 1; //规定起点为1 24 for(int i=1; i<=n; i++) 25 dis[i] = inf; 26 dis[s] = 0; 27 28 for(int k=1; k<=n; k++) 29 for(int i=0; i<cnt; i++){ 30 int x = e[i].u, y = e[i].v, z = e[i].w; 31 if(dis[x] > dis[y] + z){ 32 dis[x] = dis[y] + z; 33 pre[x] = y; //如果经过y点到x点距离更短,则更新距离,并记录路径 34 } 35 } 36 //print_path(s,?) 如果有需要,打印路径 37 } 38 39 int main(){ 40 while(~scanf("%d %d", &n, &m) && n && m){ 41 cnt = 0; 42 while(m--){ 43 int a, b, c; 44 scanf("%d %d %d", &a, &b, &c); 45 e[cnt].u = a; e[cnt].v = b; e[cnt].w = c; cnt++;46 e[cnt].u = b; e[cnt].v = a; e[cnt].w = c; cnt++; 46 } 47 bellman(); 48 } 49 return 0; 50 }
SPFA()。SPFA是用队列处理Bellman-Ford算法,效率很高。但他并不稳定。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int inf = 0x3f3f3f3f; 5 const int num = ???; 6 struct edge{ 7 int from, to, w;//边:起点from(其实没有用到),终点to,权值(距离)w 8 edge(int a, int b, int c){from=a; to=b; w=c;} 9 }; 10 vector<edge>e[num];//第i个节点连接的所有边 11 int n, m; 12 int dis[num];//从规定起点到点i的距离 13 int pre[num];//记录路径 14 15 //打印路径 16 void print_path(int s, int t){ 17 if(s == t){printf("%d",s); return ;} 18 print_path(s, pre[t]); 19 printf("->%d",t); 20 } 21 22 int spfa(int s){ 23 bool inq[num];//标记节点i是否在队列中 24 int neg[num];//判断负圈 25 //初始化 26 for(int i=1; i<=n; i++){ 27 neg[i] = 0; 28 dis[i] = inf; 29 inq[i] = false; 30 } 31 neg[s] = 1; 32 // 33 queue<int>q; 34 q.push(s); 35 inq[s] = true;//s进队 36 // 37 while(!q.empty()){ 38 int u = q.front(); 39 q.pop(); 40 inq[u] = false;//s出队 41 42 for(int i=0; i<e[u].size(); i++){//检查节点u连接的所有边 43 int v = e[u][i].to, w = e[u][i].w; 44 if(dis[u] + w < dis[v]){//起点->u->v的距离 < 起点->v的距离 45 dis[v] = dis[u] + w; 46 pre[v] = u; 47 if(!inq[v]){//如果v不在队列则插入 48 inq[v] = true; 49 q.push(v); 50 neg[v]++; 51 if(neg[v] > n) return 1;//v的更新次数超过节点个数,则说明存在负圈 52 } 53 } 54 } 55 } 56 //print_path(s,?); 57 return 0; 58 } 59 60 int main(){ 61 while(~scanf("%d %d", &n, &m) && n && m){ 62 for(int i=1; i<=n; i++) e[i].clear(); 63 while(m--){ 64 int a, b, c; 65 scanf("%d %d %d", &a, &b, &c); 66 e[a].push_back(edge(a,b,c)); 67 e[b].push_back(edge(b,a,c)); 68 } 69 spfa(1);//规定1为起点 70 } 71 return 0; 72 }
SPFA()-链式前向星。极端情况下,图特别大,用邻接链表也会超空间限制,此时需要用到链式前向星来存图。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int inf = INT_MAX / 10; 5 const int num = ???; 6 struct Edge{ 7 int to, next, w;//edge[i]的i就是起点,终点to,权值w,相同起点的下一条边next 8 }edge[num]; 9 int n, m, cnt; 10 int head[num];//head[i]存放以i为起点的下一条边 11 int dis[num]; 12 int inq[num];//标记节点是否在队列中 13 int neg[num];//判负圈 14 int pre[num];//记录前驱节点 15 16 void print_path(int s, int t){ 17 if(s==t) {printf("%d",s); return ;} 18 print_path(s, pre[t]); 19 printf("->%d",t); 20 } 21 22 //初始化 23 void init(){ 24 for(int i=0; i<num; ++i){ 25 edge[i].next = -1; 26 head[i] = -1; 27 } 28 cnt = 0; 29 } 30 31 //加边 32 void addedge(int u, int v, int w){ 33 edge[cnt].to = v; 34 edge[cnt].w = w; 35 edge[cnt].next = head[u];//指向上一条同起点的边 36 head[u] = cnt;//存放以u为起点的某条边edge的下标 37 cnt++; 38 } 39 40 int spfa(int s){ 41 for(int i=1; i<=n; ++i){ 42 neg[i] = 0; 43 dis[i] = inf; 44 inq[i] = false; 45 } 46 neg[s] = 1; 47 dis[s] = 0; 48 49 queue<int>q; 50 q.push(s); 51 inq[s] = true; 52 53 while(!q.empty()){ 54 int u = q.front(); 55 q.pop(); 56 inq[u] = false; 57 58 for(int i=head[u]; ~i; i=edge[i].next){//~1 即 i!=-1 59 int v = edge[i].to; 60 int w = edge[i].w; 61 if(dis[u] + w < dis[v]){ 62 dis[v] = dis[u] + w; 63 pre[v] = u; 64 if(!inq[v]){ 65 inq[v] = true; 66 q.push(v); 67 neg[v]++; 68 if(neg[v] > n) return 1;//v的更新次数超过节点个数n,即说明存在负圈 69 } 70 } 71 } 72 } 73 //print_path(s,?); 74 return 0; 75 } 76 77 int main(){ 78 while(~scanf("%d %d", &n, &m) && n && m){ 79 //初始化 80 init(); 81 // 82 while(m--){ 83 int a, b, c; 84 scanf("%d %d %d", &a, &b, &c); 85 addedge(a, b, c); 86 addedge(b, a, c); 87 } 88 // 89 spfa(1); 90 } 91 return 0; 92 }
dijkstra()
1 #include<bits/stdc++.h> 2 #include<vector> 3 #include<queue> 4 using namespace std; 5 6 const int inf = 0x3f3f3f3f; 7 const int num = ???; 8 struct edge{ 9 int from, to, w; 10 edge(int a, int b, int c){from=a; to=b; w=c;} 11 }; 12 vector<edge>e[num]; 13 struct node{ 14 int id, n_dis;//id节点,n_dis节点到起点的距离 15 node(int b, int c){id=b; n_dis=c;} 16 bool operator <(const node &a)const 17 { return n_dis > a.n_dis;} 18 }; 19 int n, m, s; 20 int pre[num]; 21 int dis[num]; 22 bool done[num]; 23 24 void print_path(int s, int t){ 25 if(s==t){printf("%d",s); return ;} 26 print_path(s, pre[t]); 27 printf("->%d",t); 28 } 29 30 void dijkstra(){ 31 // 32 s= 1; 33 for(int i=1; i<=n; ++i){ 34 dis[i] = inf; 35 done[i] = false; 36 } 37 dis[s] = 0; 38 // 39 priority_queue<node>q; 40 q.push(node(s, dis[s])); 41 // 42 while(!q.empty()){ 43 node u = q.top(); 44 q.pop(); 45 // 46 if(done[u.id]) continue; 47 // 48 done[u.id] = true; 49 for(int i=0; i<e[u.id].size(); ++i){ 50 edge y = e[u.id][i]; 51 // 52 if(done[y.to]) continue; 53 // 54 if(dis[y.to] > y.w + u.n_dis){ 55 dis[y.to] = y.w + u.n_dis; 56 q.push(node(y.to, dis[y.to])); 57 pre[y.to] = u.id; 58 } 59 } 60 } 61 //print_path(s,?); 62 } 63 64 int main(){ 65 while(~scanf("%d %d", &n, &m) && n && m){ 66 // 67 for(int i=1; i<=n; ++i) e[i].clear(); 68 // 69 while(m--){ 70 int a, b, c; 71 scanf("%d %d %d", &a, &b, &c); 72 e[a].push_back(edge(a, b, c)); 73 e[b].push_back(edge(b, a, c)); 74 } 75 // 76 dijkstra(); 77 } 78 return 0; 79 }
1.0 Floyd(),简单粗暴,三重循环遍历,可求多源两点距离,但毕竟复杂度高,不适合过大的图。
2.0 Bellman(),借用一个(存放起点u、终点v、权值w的)结构体edge,遍历次数取决于边的个数*节点个数n,将复杂的三重循环,缩小到O(nm)的复杂度。
2.1 在Bellman()的基础上增设一个标记数组neg[],用于判断负圈。
3.0 SPFA(),在Bellman的基础上,增加了一个vector<edge>e[num],将同起点的边归类,再次减小复杂度。同时在函数中用到了队列,类似于BFS,取出队首的节点以后,遍历以该节点为起点的所有边,然后依次将终点插入队尾。
3.1 SPFA()链式前向星,原模板仍有缺陷,遇到特别大的图时,用邻接表也会超空间限制,此时就需要用链式前向星来存图。摒弃了上一模板使用的vector,重用结构体数组,并在结构体中增设next指向同起点的下一条边,增设了数组head[],用联系同一起点的前后两条边。同时增设addedge函数应对复杂起来的加边程序。链式前向星是用来应对图过大,节点过多的情况,减小空间复杂度。
4.0 dijkstra(),大体是在原版的SPFA的基础上,改用了优先队列priority_queue,能够更快地找到某个节点的最短路径, 以减小时间复杂度。
标签:event 选择 const 需要 bit queue floyd 节点 tor
原文地址:https://www.cnblogs.com/0424lrn/p/12262862.html