最短路径

来源:互联网 发布:尼尔森零售监测数据 编辑:程序博客网 时间:2024/05/21 07:56

一:单源最短路径
1.Dijkstra:从源点开始,然后开始扩展节点,更新边
因为用了优先级队列来优化找最小值的过程,时间复杂度为O(elogv)

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <queue>using namespace std;#define maxn 105#define MAX 0x3f3f3f3fstruct edge{  int to,next,v;};struct node{  int to,v;  bool operator <(const node &t)const{         return v>t.v;  }};edge e[maxn*maxn];int head[maxn];int dis[maxn];int vis[maxn];priority_queue<node> q;void add(int h,int a,int b,int c){    e[h].to=b,e[h].next=head[a];    e[h].v=c,head[a]=h;}int main(){  int n,m;  while(scanf("%d %d",&n,&m)!=EOF&&m+n)  {    memset(head,-1,sizeof(head));    memset(e,0,sizeof(e));    int h=0;    for(int i=0;i<m;i++)    {      int a,b,c;      scanf("%d %d %d",&a,&b,&c);      add(h,a,b,c);      h++;      add(h,b,a,c);      h++;    }    memset(dis,MAX,sizeof(dis));    memset(vis,0,sizeof(vis));    while(!q.empty())      q.pop();    dis[1]=0;    vis[1]=1;    q.push(node{1,0});    while(!q.empty())    {      node t=q.top();      q.pop();      if(vis[t.to])        continue;      vis[t.to]=1;      for(int i=head[t.to];i>-1;i=e[i].next)      {        edge g=e[i];        if(dis[g.to]>g.v+t.v)        {          dis[g.to]=g.v+t.v;          q.push(node{g.to,dis[g.to]});        }      }    }    printf("%d\n",dis[n]);  }  return 0;}

2.Bellman-Ford (对每条边进行松弛,可以判负环)
时间复杂度为 O(v*e)(节点数*总边数)

参考:http://www.cnblogs.com/tanky_woo/archive/2011/01/17/1937728.html

模板

bool Bellman_Ford()  {     memset(dis,MAX,sizeof(dis));    dis[original]=0;    for(int i = 1; i <= nodenum - 1; ++i)  //边数        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;  }  

二:任意两点间的最短路问题
Floyd-Warshall
也可以处理边是负数的问题,判断负环,只用判断d[i][i]是不是负数

void warshall_floyd(){    for(int k=0;k<v;k++)    {        for(int i=0;i<v;i++)        {            for(int j=0;j<v;j++)            {                d[i][j]=min(d[i][j],d[i])            }        }    }}

路径还原,只用加一个数组里面放前驱。