最短路总结

来源:互联网 发布:域名投资人联系 编辑:程序博客网 时间:2024/06/05 17:16

今天是我入队的第180天。不知道以后的路还有多长,但还是要坚持下去!

一直学习别人的东西,看别人的总结,这次我也想自己写一份总结,也算不辜负我这半年的付出。

最早接触的算法应该就是最短路了,整整半年了,现在终于有资本说自己还是懂那么一种算法的。

之前学的时候总想把dijkstra,bellman ford,spfa,floyd全都总结出来,但网上的资料很零散,所以就把这次的总结当做我对acm的一点贡献吧~(大神勿喷,我还只能算是一个算法入门者)

以下总结基本都以hdu2544为例

1.dijkstra 邻接矩阵形式

#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>#include <stack>#include <queue>#include <vector>#include <map>#include <set>#include <string>#include <sstream>using namespace std;const int INF= 1<<30;const int MAX=1050;int dis[MAX],n,m;int edges[MAX][MAX];int visit[MAX];//最小下标为1void dijkstra(int v){int i,j;int u;memset(visit,0,sizeof(visit));//标记是否已求出最短路径fill(dis+1,dis+n+1,INF);dis[v]=0;while(1)//最多循环n次就够了,每次找到 v到某一个点的最短路{u=-1;for(j=1;j<=n;j++)//找当前最短if((!visit[j])&&(u==-1||dis[j]<dis[u]))u=j;if(u==-1)break;visit[u]=1;for(j=1;j<=n;j++)//更新当前所有的最短路径if((!visit[j])&&(edges[u][j]<INF)&&(dis[u]+edges[u][j])<dis[j])dis[j]=dis[u]+edges[u][j];}}int main(){int i,j,a,b,c;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)return 0;for(i=0;i<MAX;i++)//矩阵初始化为INF{edges[i][i]=0;for(j=i+1;j<MAX;j++){edges[i][j]=INF;edges[j][i]=INF;}}for(i=0;i<m;i++)//获得各边之间的长度{scanf("%d%d%d",&a,&b,&c);if(edges[a][b]>c){edges[a][b]=c;edges[b][a]=c;}}dijkstra(1);//求以1为起点到各点的最短路径printf("%d\n",dis[n]);}return 0;}
2.dijkstra邻接表形式

#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>#include <stack>#include <queue>#include <vector>#include <map>#include <set>#include <string>#include <sstream>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1typedef long long LL;const double pi=4.0*atan(1.0);const int MAX=105;const int INF=1<<29;struct Edge{int v,val;Edge(){}Edge(int _v,int _val):v(_v),val(_val){}};vector<Edge> g[MAX];int n;int dis[MAX],vis[MAX];void dijkstra(int s){memset(vis,0,sizeof(vis));fill(dis+1,dis+n+1,INF);dis[s]=0;while(1){int u=-1;for(int v=1;v<=n;v++)if(!vis[v]&&(u==-1||dis[u]>dis[v]))u=v;if(u==-1)break;vis[u]=1;for(int i=0;i<g[u].size();i++){int v=g[u][i].v;if(!vis[v]&&dis[v]>dis[u]+g[u][i].val)dis[v]=dis[u]+g[u][i].val;}}}int main(){int i,j,k;int m;int x,y,z;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)return 0;for(i=1;i<=n;i++)g[i].clear();for(i=0;i<m;i++){scanf("%d%d%d",&x,&y,&z);g[x].push_back(Edge(y,z));g[y].push_back(Edge(x,z));}dijkstra(1);printf("%d\n",dis[n]);}return 0;}
3.dijkstra向前星

#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>#include <stack>#include <queue>#include <vector>#include <map>#include <set>#include <string>#include <sstream>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1typedef long long LL;const double pi=4.0*atan(1.0);const int MAXN=10005;const int MAX=105;const int INF=1<<29;struct Edge{int v,val;int next;};Edge edge[MAXN<<1];int n;int head[MAX],total;int dis[MAX],vis[MAX];void init(){memset(head,-1,sizeof(head));total=0;}void addedge(int x,int y,int z){edge[total].v=y;edge[total].val=z;edge[total].next=head[x];head[x]=total++;}void dijkstra(int s){memset(vis,0,sizeof(vis));fill(dis+1,dis+n+1,INF);dis[s]=0;while(1){int u=-1;for(int v=1;v<=n;v++)if(!vis[v]&&(u==-1||dis[u]>dis[v]))u=v;if(u==-1)break;vis[u]=1;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(!vis[v]&&dis[v]>dis[u]+edge[i].val)dis[v]=dis[u]+edge[i].val;}}}int main(){int i,j,k;int m;int x,y,z;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)return 0;init();for(i=0;i<m;i++){scanf("%d%d%d",&x,&y,&z);addedge(x,y,z);addedge(y,x,z);}dijkstra(1);printf("%d\n",dis[n]);}return 0;}
4.dijkstra优先队列优化+邻接表形式

#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>#include<vector>#include<queue>using namespace std;const int MAXN=100005;const int INF=9999999;int flag[MAXN];int dist[MAXN],n;struct Node{int id,val;Node(){}Node(int _id,int _val):id(_id),val(_val){}bool operator<(const Node &a)const{                //重载<,使优先队列队首始终是val最小的元素return val > a.val;}};struct Edge{int v,cost;                                         Edge(){}Edge(int _v,int _cost):v(_v),cost(_cost){}};vector<Edge>mp[MAXN]; //mp[i][j].v表示i的第j条边连接的是顶点v,权值为mp[i][j].costvoid dijkstra(int s){int i,j,k,v,cost;Node tep;memset(flag,0,sizeof(flag));for(i=0;i<10005;i++)dist[i]=INF;priority_queue<Node> que;dist[s] = 0;que.push(Node(s,0));                       //起点入队while(!que.empty()){tep = que.top();que.pop();if(flag[tep.id])continue;       //如果tep.id已经在集合中,不用拿出flag[tep.id] = 1;//将tep.id放入集合for(i = 0;i < mp[tep.id].size(); i++){v = mp[tep.id][i].v;cost = mp[tep.id][i].cost;if(!flag[v] && dist[v] > dist[tep.id] + cost){                //松弛dist[v] = dist[tep.id] + cost;que.push(Node(v,dist[v]));              //加入集合}}}}int main(){int i,j,k,m,T;int u,v,w;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)return 0;for(i = 1;i <= n; i++)mp[i].clear();for(i = 1;i <= m;i++){scanf("%d%d%d",&u,&v,&w);mp[v].push_back(Edge(u,w));   //双向边mp[u].push_back(Edge(v,w));}dijkstra(1);printf("%d\n",dist[n]);}          return 0;}

5.dijkstra优先队列优化+邻接矩阵

#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>#include<vector>#include<queue>using namespace std;const int MAX=105;const int INF=9999999;struct Node{int id,val;Node(){}Node(int _id,int _val):id(_id),val(_val){}bool operator<(const Node &a)const{                //重载<,使优先队列队首始终是val最小的元素return val > a.val;}};int flag[MAX];int dist[MAX],n,m;int edges[MAX][MAX];void dijkstra(int s){int i,j,k,v,cost;Node tep;memset(flag,0,sizeof(flag));for(i=0;i<MAX;i++)dist[i]=INF;priority_queue<Node> que;dist[s] = 0;que.push(Node(s,0));                                                               //起点入队while(!que.empty()){tep = que.top();que.pop();if(flag[tep.id])continue;//如果tep.id已经在集合中,不用拿出flag[tep.id] = 1;//将tep.id放入集合for(i = 1;i <= n; i++){v = i;cost = edges[tep.id][i];if(!flag[v] &&cost<INF&& dist[v] > dist[tep.id] + cost){                //松弛dist[v] = dist[tep.id] + cost;que.push(Node(v,dist[v]));                                     //加入集合}}}}int main(){int i,j,a,b,c;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)return 0;for(i=0;i<MAX;i++)//矩阵初始化为INF{for(j=0;j<MAX;j++){if(i==j)edges[i][j]=0;elseedges[i][j]=INF;}}for(i=0;i<m;i++)//获得各边之间的长度{scanf("%d%d%d",&a,&b,&c);if(edges[a][b]>c){edges[a][b]=c;edges[b][a]=c;}}dijkstra(1);//求以1为起点到各点的最短路径printf("%d\n",dist[n]);}return 0;}

6.bellman ford
#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>#include <queue>using namespace std;const int INF= 99999999;  const int MAX= 1010;  typedef struct Edge //边  {  int u;int v;  int cost;  }Edge;  Edge edge[100000];  int dis[MAX], pre[MAX];  //最小下标为1//点,     边,         起点bool Bellman_Ford(int nodenum,int edgenum,int original)  //有向图的最短路{  for(int i = 1; i <= nodenum; ++i) //初始化  dis[i] = INF;  dis[original]=0;for(int i = 0; i < nodenum - 1; i++)  //总循环 点数-1 次for(int j = 1; j <= edgenum; j++)//每条边松弛if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)  {  dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;  pre[edge[j].v] = edge[j].u;  }  bool flag = 1; //判断是否含有负权回路  for(int i = 1; i <= edgenum; ++i)  if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)  {  flag = 0;  break;}  return flag;  }  void print_path(int root) //打印最短路的路径(反向)  {  while(root != pre[root]) //前驱  {  printf("%d-->", root);  root = pre[root];  }  if(root == pre[root])  printf("%d\n", root);  }  int main()  {  int i,j;int N,M;int a,b,c;while(scanf("%d%d",&N,&M)!=EOF){if(N==0&&M==0)return 0;for(i=0;i<100000;i++){edge[i].cost=INF;edge[i].u=edge[i].v=0;}j=1;for(i=0;i<M;i++){scanf("%d%d%d",&a,&b,&c);edge[j].u=a;edge[j].v=b;edge[j++].cost=c;edge[j].u=b;edge[j].v=a;edge[j++].cost=c;} Bellman_Ford(N,M*2,1);printf("%d\n",dis[N]);}return 0;  }  
7.spfa链表

注意这个模板求的是最长路,相信你自己可以改成最短路的

#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>#include <queue>#include<map>#include<stack>#include<vector>using namespace std;const int MAX= 110;  int n,m;struct Edge{int v,cost;                                         Edge(){}Edge(int _v,int _cost):v(_v),cost(_cost){}};vector<Edge> edge[110];  int dis[MAX], pre[MAX];  int v[MAX];int visit[MAX];void spfa(int s){queue<int> k;int i,h;for(i=1;i<=n+1;i++){dis[i]=-5000;visit[i]=0;}k.push(s);dis[s]=0;visit[s]=1;while(!k.empty()){h=k.front();k.pop();visit[h]=0;for(i=0;i<edge[h].size();i++){if(dis[h]+edge[h][i].cost>dis[edge[h][i].v]){dis[edge[h][i].v]=dis[h]+edge[h][i].cost;pre[edge[h][i].v]=h; if(!visit[edge[h][i].v]){k.push(edge[h][i].v);visit[edge[h][i].v]=1;}}}}}void print_path(int root) //打印最短路的路径(反向)  {  stack<int> st;while(!st.empty())st.pop();while(root != pre[root]) //前驱  {  st.push(root);  root = pre[root];  }  if(root == pre[root])  st.push(root);printf("circuit : ");while(!st.empty()){if(st.top()==n+1){printf("1\n");break;}elseprintf("%d->",st.top());st.pop();}}  int main()  {  int i,j,k;int a,b,c;int T;int cas=1;while(scanf("%d",&T)!=EOF){cas=1;while(cas<=T){if(cas!=1)printf("\n");scanf("%d",&n);for(i=1;i<=n+1;i++)edge[i].clear();for(i=1;i<=n;i++)scanf("%d",v+i);v[n+1]=0;for(i=0;i<=n+1;i++)pre[i]=i;scanf("%d",&m);for(i=1;i<=m;i++){scanf("%d%d",&a,&b);   edge[a].push_back(Edge(b,v[b]));}spfa(1);printf("CASE %d#\n",cas++);printf("points : %d\n",dis[n+1]);print_path(n+1);}}return 0;  }  

8.spfa邻接矩阵

#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>#include <queue>using namespace std;const int INF= 99999999;  const int MAX= 1010;  int n,m,edges[MAX][MAX];int visit[MAX];int dis[MAX];void spfa(int s){queue<int> k;int i,h;for(i=1;i<=n;i++){dis[i]=INF;visit[i]=0;}k.push(s);dis[s]=0;visit[s]=1;while(!k.empty()){h=k.front();k.pop();visit[h]=0;for(i=1;i<=n;i++){if(edges[h][i]<INF&&dis[h]+edges[h][i]<dis[i]){dis[i]=dis[h]+edges[h][i];if(!visit[i]){k.push(i);visit[i]=1;}}}}}int main(){int i,j;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)return 0;for(i=0;i<=n;i++)//矩阵初始化为INF{for(j=0;j<=n;j++){if(i==j)edges[i][j]=0;elseedges[i][j]=INF;}}int a,b,c;for(i=0;i<m;i++){scanf("%d%d%d",&a,&b,&c);if(edges[a][b]>c){edges[a][b]=c;edges[b][a]=c;}}     spfa(1);printf("%d\n",dis[n]);}return 0;}
9.floyd

#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>using namespace std;const int INF= 999999999;const int N=1005;int n,m;int edges[N][N];//最小下标为 1void floyd()    //Floyd算法  {  int i, j, k;  //最外层 节点个数次 循环for(k = 1; k <= n; k++)     //k为中间点  for(i = 1; i <= n; i++)  for(j = 1; j <= n; j++)  if(edges[i][k]!=INF&&edges[k][j]!=INF)if(edges[i][k] + edges[k][j] <  edges[i][j])  edges[i][j] = edges[i][k] + edges[k][j];  }  int main(){int i,j,a,b,c;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)return 0;for(i=0;i<N;i++)//矩阵初始化为INF{edges[i][i]=0;for(j=i+1;j<N;j++){edges[i][j]=INF;edges[j][i]=INF;}}for(i=0;i<m;i++)//获得各边之间的长度{scanf("%d%d%d",&a,&b,&c);if(edges[a][b]>c){edges[a][b]=c;edges[b][a]=c;}}floyd();printf("%d\n",edges[1][n]);}return 0;}
没什么注释,希望能对你们学最短路有帮助~

0 0
原创粉丝点击