zoukankan      html  css  js  c++  java
  • NO2——最短路径

    【Dijkstra算法】

    • 复杂度O(n2
    • 权值必须非负
     1 /*    求出点beg到所有点的最短路径    */ 
     2 //    邻接矩阵形式 
     3 //    n:图的顶点数
     4 //    cost[][]:邻接矩阵 
     5 //    pre[i]记录beg到i路径上的父结点,pre[beg]=-1
     6 //    返回:各点的最短路径lowcost[]以及路径pre[]
     7 const int maxn=1010; 
     8 const int INF=0x3f3f3f3f;        //防止后面溢出,这个不能太大 
     9 bool vis[maxn]; 
    10 int pre[maxn]; 
    11 void Dijkstra(int cost[][maxn],int lowcost[],int n,int beg) 
    12 { 
    13   for(int i=0;i<n;i++)       //点的编号从0开始
    14   { 
    15     lowcost[i]=INF;vis[i]=false;pre[i]=-1; 
    16   } 
    17   lowcost[beg]=0; 
    18   for(int j=0;j<n;j++) 
    19   { 
    20     int k=-1; 
    21     int Min=INF; 
    22     for(int i=0;i<n;i++) 
    23       if(!vis[i]&&lowcost[i]<Min) 
    24       { 
    25         Min=lowcost[i]; 
    26         k=i; 
    27       } 
    28     if(k==-1)break; 
    29     vis[k]=true; 
    30     for(int i=0;i<n;i++) 
    31       if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i]) 
    32       { 
    33         lowcost[i]=lowcost[k]+cost[k][i]; 
    34         pre[i]=k; 
    35       } 
    36   } 
    37 } 

    【Dijkstra算法+堆优化】

    • 复杂度O(E*logE)
    • 使用优先队列优化Dijkstra算法
     1 //注意对vector<Edge>E[MAXN]进行初始化后加边
     2 const int INF=0x3f3f3f3f; 
     3 const int maxn=1000010; 
     4 struct qnode 
     5 { 
     6       int v; 
     7       int c; 
     8       qnode(int _v=0,int _c=0):v(_v),c(_c){} 
     9       bool operator <(const qnode &r)const 
    10       { 
    11         return c>r.c; 
    12       } 
    13 }; 
    14 struct Edge 
    15 { 
    16       int v,cost; 
    17       Edge(int _v=0,int _cost=0):v(_v),cost(_cost){} 
    18 }; 
    19 vector<Edge>E[maxn]; 
    20 bool vis[maxn]; 
    21 int dist[maxn]; 
    22 void Dijkstra(int n,int start)        //点的编号从1开始 
    23 { 
    24     memset(vis,false,sizeof(vis)); 
    25       for(int i=1;i<=n;i++)dist[i]=INF; 
    26       priority_queue<qnode>que; 
    27       while(!que.empty())que.pop(); 
    28       dist[start]=0; 
    29       que.push(qnode(start,0)); 
    30       qnode tmp; 
    31       while(!que.empty()){
    32           tmp=que.top(); 
    33         que.pop(); 
    34         int u=tmp.v; 
    35         if(vis[u])continue; 
    36         vis[u]=true; 
    37         for(int i=0;i<E[u].size();i++){ 
    38               int v=E[tmp.v][i].v; 
    39               int cost=E[u][i].cost; 
    40               if(!vis[v]&&dist[v]>dist[u]+cost){ 
    41                 dist[v]=dist[u]+cost; 
    42                 que.push(qnode(v,dist[v])); 
    43               } 
    44         } 
    45       } 
    46 } 
    47 void addedge(int u,int v,int w) 
    48 {
    49     E[u].push_back(Edge(v,w)); 
    50 } 

    【Bellman-ford算法】

    • 复杂度O(V*E)
    • 可以处理负边权图
     1 //可以判断是否存在负环回路
     2 //返回true,当且仅当图中不包含从源点可达的负权回路 
     3 //vector<Edge>E;
     4 //先E.clear()初始化,然后加入所有边 
     5 const int INF=0x3f3f3f3f; 
     6 const int maxn=550; 
     7 int dist[maxn]; 
     8 struct Edge 
     9 { 
    10   int u,v; 
    11   int cost; 
    12   Edge(int _u=0,int _v=0,int _cost=0):u(_u),v(_v),cost(_cost){}     //构造函数 
    13 }; 
    14 vector<Edge>E; 
    15 bool bellman_ford(int start,int n)    //点的编号从1开始 
    16 { 
    17   for(int i=1;i<=n;i++)dist[i]=INF; 
    18   dist[start]=0; 
    19   for(int  i=1;i<n;i++)            //最多做n-1次 
    20   { 
    21     bool flag=false; 
    22     for(int j=0;j<E.size();j++) 
    23     { 
    24       int u=E[j].u; 
    25       int v=E[j].v; 
    26       int cost=E[j].cost; 
    27       if(dist[v]>dist[u]+cost) 
    28       { 
    29         dist[v]=dist[u]+cost; 
    30         flag=true; 
    31       } 
    32     } 
    33     if(!flag)return  true;    //没有负环回路 
    34   } 
    35   for(int j=0;j<E.size();j++) 
    36     if(dist[E[j].v]>dist[E[j].u]+E[j].cost) 
    37       return false;    //有负环回路 
    38   return true;        //没有负环回路 
    39 } 

    【SPFA算法】

    • 复杂度O(K*E)
     1 //这个是队列实现,有时候改成栈实现会更加快,很容易修改 
     2 //这个复杂度是不定的 
     3 const int maxn=1010; 
     4 const int INF=0x3f3f3f3f; 
     5 struct Edge 
     6 { 
     7   int v; 
     8   int cost; 
     9   Edge(int _v=0,int _cost=0):v(_v),cost(_cost){} 
    10 }; 
    11 vector<Edge>E[maxn]; 
    12 void addedge(int u,int v,int w) 
    13 { 
    14   E[u].push_back(Edge(v,w)); 
    15 } 
    16 bool vis[maxn];                //在队列标志 
    17 int cnt[maxn];                //每个点的入队列次数 
    18 int dist[maxn]; 
    19 bool SPFA(int start,int n) 
    20 { 
    21   memset(vis,false,sizeof(vis)); 
    22   for(int i=1;i<=n;i++)dist[i]=INF; 
    23   vis[start]=true; 
    24   dist[start]=0; 
    25   queue<int>que; 
    26   while(!que.empty())que.pop(); 
    27   que.push(start); 
    28   memset(cnt,0,sizeof(cnt)); 
    29   cnt[start]=1; 
    30   while(!que.empty()) 
    31   { 
    32     int u=que.front(); 
    33     que.pop(); 
    34     vis[u]=false; 
    35     for(int i=0;i<E[u].size();i++) 
    36     { 
    37       int v=E[u][i].v; 
    38       if(dist[v]>dist[u]+E[u][i].cost) 
    39       { 
    40         dist[v]=dist[u]+E[u][i].cost; 
    41         if(!vis[v]) 
    42         { 
    43           vis[v]=true; 
    44           que.push(v); 
    45           if(++cnt[v]>n)return false;         //cnt[i]为入队列次数,用来判定是否存在负环回路 
    46         } 
    47       } 
    48     } 
    49   } 
    50   return true; 
    51 } 

    Floyd-Warshall算法

    • 复杂度O(n3
    • 边权非负
     1 #include<cstdio>  
     2 using namespace std;  
     3 #define INF 1e9  
     4 const int maxn=100+10;  
     5 int n,m;                //点数,边数,点从0到n-1编号  
     6 int dist[maxn][maxn];    //记录距离矩阵  
     7 int path[maxn][maxn];    //path[i][j]=x表示i到j的路径上(除i外)的第一个点是x.  
     8 void init()  
     9 {  
    10     for(int i=0;i<n;i++)  
    11     for(int j=0;j<n;j++)  
    12     {  
    13         dist[i][j] = i==j ? 0 : INF;    //其实这里d[i][j]应该还要通过输入读数据的  
    14         path[i][j] = j;  
    15     }  
    16   
    17     //读取其他dist[i][j]的值  
    18 }  
    19 void floyd()  
    20 {  
    21     for(int k=0;k<n;k++)  
    22     for(int i=0;i<n;i++)  
    23     for(int j=0;j<n;j++)  
    24     if(dist[i][k]<INF && dist[k][j]<INF )  
    25     {  
    26         if(dist[i][j]>dist[i][k]+dist[k][j])  
    27         {  
    28             dist[i][j] = dist[i][k]+dist[k][j];  
    29             path[i][j] = path[i][k];  
    30         }  
    31         else if(dist[i][j] == dist[i][k]+dist[k][j] &&path[i][j]>path[i][k])  
    32         {  
    33             path[i][j] = path[i][k];  //最终path中存的是字典序最小的路径  
    34         }  
    35     }  
    36 }  
    37   
    38 int main()  
    39 {  
    40     //读n和m  
    41     init();  
    42     //读m条边  
    43     floyd();  
    44     //输出所求最短路径距离  
    45     return 0;  
    46 }  
  • 相关阅读:
    ccf 201604-3 路径解析
    ccf 201609-3 炉石传说
    ccf 201612-3 权限查询
    ccf 201709-3 JSON查询
    ccf 201703-3 Markdown
    POJ 3259 -- Wormholes
    Bellman-Ford 单源最短路径算法
    【oracle】oracle启动和关闭步骤
    【Excel】Excel根据单元格背景色求和
    【Oracle】Oracle时间日期格式
  • 原文地址:https://www.cnblogs.com/xzxl/p/7295666.html
Copyright © 2011-2022 走看看