最短距离模板

来源:互联网 发布:js控制display显示 编辑:程序博客网 时间:2024/06/06 07:05

dijkstra算法:求指定两点间的距离(不适用负边权),O(n^2)

#include<iostream>  #include<vector>  #include<cstdio>  using namespace std;const int INF = 0x3fffffff;const int MAXV = 105;int map[MAXV][MAXV], d[MAXV];//map存地图,d存到此点的最短路径   bool vis[MAXV];//存是否访问过   //int pre[MAXV];//pre[k]表示从起点到顶点k的最短路径上k的前一个顶点   //int c[MAXV],cost[MAXV][MAXV];//新增边权 ,边权最小   //int w[MAXV],weight[MAXV];//新增点权 ,w从起点到此点的最大点权 ,点权最大   //int num[MAXV]; //求最短路径条数   void dijkstra(int n, int s)//n为总点数,s为起点   {fill(vis, vis + MAXV, false);fill(d, d + MAXV, INF);//初始化为最大   //  fill(c, c + MAXV, INF);    //memset(num,0,sizeof(num));    //memset(w,0,sizeof(w));   d[s] = 0;//起点初始化为0     //c[s]=0;    //w[s]=weight[s];    //num[s]=1; //第一个点为 1,别的全为0   for (int i = 0; i < n; i++)//遍历每个点   {int u = -1, Min = INF;//u使d[u]最小,Min存最小的d[u]   for (int j = 1; j <= n; j++)//寻找未访问点中最小的   {if (vis[j] == false && d[j] < Min)//寻找最小的点   {u = j;Min = d[j];}}if (u == -1)return;//不连通,返回   vis[u] = true;//标记为已访问   for (int k = 1; k <= n; k++)//更新与u点相连接点的最优解   {//k未访问&&以u为中介点可以使d[k]更优   if (vis[k] == false && map[u][k] != INF){if (d[u] + map[u][k] < d[k])//如果是更优解   {d[k] = d[u] + map[u][k];//pre[k]=u;//存前面的点   //c[k]=c[u]+cost[u][k];//w[k] = w[u] + weight[k];  //num[k] = num[u];  }/*else if(d[u] + map[u][k] == d[k])//如有第二权值,且需求路径,更新第二权值时更新路径{if(w[u]+weight[k]>w[k])//最短距离相同时能使w[k]更优{w[k]=w[u]+weight[k];//pre[k]=u;}if(c[u]+cost[u][k]<c[k])//最短距离相同时能使c[k]更优{c[k]=c[u]+cost[u][k];//pre[k]=u;}num[k]+=num[u];//最短距离相同时累加num}*/}}}}/*void dfs(int s,int v)//最短路径只有一条时,输出最短路径{if(v==s){printf("%d\n",s);return;}dfs(s,pre[v]);printf("%d\n",v);}*/int main(){int i, x, y, z, n, m, s, t;//n为总点数,m为输入路径数   while (scanf("%d %d",&n,&m)!=EOF&&m&&n){fill(map[0], map[0] + MAXV*MAXV, INF);//初始化map   for (i = 1; i <= m; i++){scanf("%d %d %d",&x,&y,&z);if (map[x][y]>z)//防重边   map[x][y] = map[y][x] = z;//无向边   }s = 1;//起点dijkstra(n,s);//s起点为1   t = n;//t为终点cout << d[t] << endl;//输出终点的最短路径   }return 0;}

floyd算法:可以求出任意两点间的最短距离,O(n^3)

#include<iostream>#include<cstdio>using namespace std;const int INF = 0x3fffffff;const int MAXV = 1005;int map[MAXV][MAXV];//map存地图void floyd(int n){for(int i=1;i<=n;i++)map[i][i]=0; //i到i点初始化为0 for(int k=1;k<=n;k++)//找出一个中介点 使map[i][j]更优 {for(int i=1;i<=n;i++){if(map[i][k]==INF)continue;//不连通 for(int j=1;j<=n;j++)if(map[k][j]!=INF&&map[i][k]+map[k][j]<map[i][j])//若通过此点更优 map[i][j]=map[i][k]+map[k][j];}}}int main(){int i, x, y, z, n, m, s, t;//n为总点数,m为输入路径数   while (scanf("%d %d",&n,&m)!=EOF&&m&&n){fill(map[0], map[0] + MAXV*MAXV, INF);//初始化map  for (i = 1; i <= m; i++){scanf("%d %d %d",&x,&y,&z);if (map[x][y]>z)//防重边 map[x][y] = map[y][x] = z;//无向边   }   floyd(n);s=1;//起点 t=n;//终点 cout << map[s][t] << endl;//输出任意两点的最短路径   }return 0; } 

spfa算法,可用于有负边权

#include<iostream>#include<vector>#include<queue>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int INF = 0x3fffffff;const int MAXV = 1005;struct node{int v, dis;//v为目标顶点,dis为边权 };vector<node> adj[MAXV];//图的邻接表 int n, m, d[MAXV], num[MAXV];//d存到此点的最短路径,num记录顶点入队的次数 bool inq[MAXV];//顶点是否在队列中 bool spfa(int s){memset(inq, false, sizeof(inq));memset(num, 0, sizeof(num));fill(d, d + MAXV, INF);queue<int> q;q.push(s);//源点入队 inq[s] = true;num[s]++;//源点入队次数加1 d[s] = 0;//源点d值为0 while (!q.empty()){int u = q.front();//队首顶点编号u q.pop();inq[u] = false;//设u不在队列 for (int j = 0; j<adj[u].size(); j++)//遍历u的所有邻接边v {int v = adj[u][j].v;int dis = adj[u][j].dis;if (d[u] + dis<d[v])//松弛操作 {d[v] = d[u] + dis;if (!inq[v])//如果v不在队列中 {q.push(v);inq[v] = true;num[v]++;if (num[v] >= n)return false;//有可达负环 }}}}return true;//无可达负环 }int main(){int cost, a, b, s, t;//a点到b点的花费为cost node k;//临时结构体,输入用 while (scanf("%d %d", &n, &m) != EOF&&m&&n){for (int i = 0; i < MAXV; i++)adj[i].clear();for (int i = 0; i<m; i++)//m为点数,m为输入的边数 {scanf("%d %d %d", &a, &b, &cost);k.v = b;k.dis = cost;adj[a].push_back(k);//无向边 k.v = a;adj[b].push_back(k);}s = 1;//起点 t = n;//终点 if (spfa(s))printf("%d\n", d[t]);else printf("出现负环,最短路径不存在\n");}}