zoukankan      html  css  js  c++  java
  • 图论---------最短路专题

    在学习以下算法之前必须要有很好的建图基础。

    存图一般用

      邻接矩阵  

      邻接表   

      前向星/链式前向星  

      vector模拟邻接矩阵  

    知道以上存图工具,下来正式开始码算法了

    一.Floyd

      时间复杂度O(n的三次方),容易理解

      Floyd是一个最入门的最短路的求值过程,思想有点偏向dp。

      

     1 int mp[110][110];//  例如;mp[x][y]存的是:x结点到y结点的最短路值为mp[x][y] 
     2 int main(){
     3 /*
     4     算法的思想:
     5         先进行初始化,对于i==j的情况,则mp[i][j]=0;
     6         否则   mp[i][j]=inf  (这里的inf为无穷大)
     7     然后再寻  i到j的路中是否可以经过中间结点k,使得i到j的距离更短
     8         即:mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]) 
     9     经过三重循环就能得到最优解 
    10 */     

    算法实现:

     1 #include<iostream>
     2 using namespace std;
     3 int n,m,mp[110][110];
     4 const int inf=9999999;
     5 void init(){
     6     cin>>n>>m;//n个点 m条边 
     7     for (int i=1;i<=n;i++){
     8         for (int j=1;j<=n;j++){
     9             mp[i][j]=(i==j?0:inf); 
    10         }
    11     }
    12     int u,v,w;   //结点u到结点v的权值为w (这里为有向边)  
    13     for (int i=1;i<=m;i++){
    14         cin>>u>>v>>w;
    15         mp[u][v]=min(mp[u][v],w); 
    16     }
    17 }
    18 void Floyd(){    //算法实现 
    19     for (int k=1;k<=n;k++){
    20         for (int i=1;i<=n;i++){
    21             for (int j=1;j<=n;j++){
    22                 mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
    23             }
    24         }
    25     }
    26 }
    27 int main(){
    28     init();
    29     Floyd();
    30     int u,v;
    31     while (cin>>u>>v){
    32         printf("结点%d到结点%d的最短距离为%d
    ",u,v,mp[u][v]);
    33     }
    34     return 0;
    35 }

    自测数据:

      

    4 8
    1 2 2
    1 3 6
    1 4 4
    2 3 3
    3 1 7
    3 4 1
    4 1 5
    4 3 12

    1 2 结点1到结点2的最短距离为2 1 3 结点1到结点3的最短距离为5 1 4 结点1到结点4的最短距离为4 2 3 结点2到结点3的最短距离为3 2 4 结点2到结点4的最短距离为4 3 4 结点3到结点4的最短距离为1 4 3 结点4到结点3的最短距离为10

    推荐题目:
    P2910  P2017  hdu 2544

      这个算法尽管很容易理解,但是复杂度过高,很多问题都难以解决。下面推出Dijkstra。

    二. Dijkstra

      时间复杂度 O(n*m)

      缺点:不能处理负权边

    推荐题目:

    hdu 2066

      

    三.Bellman-Ford

      复杂度O(n*m)

      建立一个dis[]数组,例如:dis【n】记录的是    源点到结点n的最短距离

      

     1 /*
     2     算法伪码:
     3     dis[len];
     4     while (一般跳出条件为dis不能再次更新的时候){  //当出现负环的时候就成死循环了,看题目具体而议 
     5     
     6         for (一个顶点编号--->最后一个结点编号){
     7             遍历该结点的所有边
     8                 例如:该结点编号为u,有一个通向结点v的有向边权值为w 
     9                 执行:
    10                      dis[v]=min(dis[v],dis[u]+w);                     
    11         }
    12     }     
    13 */ 
    Bellman-Ford

    题目推荐:

       poj 3259

    四.SPFA

      时间复杂度O(nm)

      就是经过队列优化的Bellman-Ford

    优化操作:将顶点存入队列中(存入的时候记得要标记),然后依次取出,看是否符合更新边的条件。

    贴一题:POJ:3259

     1 /*
     2     题意:
     3     测试样例的第一行:
     4         n,m,w    分别代表结点数,权值为正的双向边数, 权值为负的单向边边数 
     5     下面接着m行:
     6         每行三个整数:u,v,w    结点u与结点v的双向边权值为w
     7     下面接着w行:
     8         每行三个整数:u,v,w       结点u到结点v的权值为 -w 
     9     
    10     翻译过来就是要求 
    11         如果存在dis【n】为负数的情况输出YES
    12         否则输出NO 
    13 */ 
    1 /*
    2     思路:
    3         其实就是判定存不存在负环
    4         
    5         解决方法:
    6             如果存在负环,那么肯定有一个结点n可以无限更新dis[n]值 
    7             当更新次数为>=n的时候,就一定存在负环,所以循环在这里跳出          
    8 */ 
    思路
     1 #include<iostream>
     2 #include<vector>
     3 #include<queue>
     4 #include<cstring>
     5 using namespace std;
     6 const int MAXN=550,MAXM=6010,inf=99999999;
     7 int n,m,w,dis[MAXN],cnt[MAXN];
     8 struct Edge{
     9     int u,v,w;
    10 }e[MAXM];
    11 bool vis[MAXN];
    12 vector<Edge>vec[MAXN];
    13 void init(){
    14     cin>>n>>m>>w;
    15     for (int i=0;i<=n;i++){
    16         vec[i].clear();
    17         dis[i]=inf;
    18         cnt[i]=0;
    19     }
    20     memset(vis,false,sizeof(vis));
    21     Edge tmp;    
    22     for (int i=1;i<=m;i++){
    23         scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    24         vec[e[i].u].push_back(e[i]);
    25         tmp.u=e[i].v;
    26         tmp.v=e[i].u;
    27         tmp.w=e[i].w;
    28         vec[e[i].v].push_back(tmp);
    29     }
    30     for (int i=1;i<=w;i++){
    31         scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    32         tmp.u= e[i].u;
    33         tmp.v= e[i].v;
    34         tmp.w=-e[i].w;
    35         vec[e[i].u].push_back(tmp);                
    36     }
    37     return ;
    38 }
    39 
    40 bool spfa(int u){
    41     dis[u]=0;
    42     queue<int>q;
    43     while (!q.empty())
    44         q.pop();
    45     q.push(u);
    46     while (!q.empty()){
    47         int s=q.front();
    48         q.pop();
    49         if (cnt[s]>=n)
    50             return true;
    51         for (int i=0;i<vec[s].size();i++){        
    52             if (vis[vec[s][i].v]==false||dis[vec[s][i].v]>dis[s]+vec[s][i].w){
    53                 vis[vec[s][i].v]=true;
    54                 if (dis[vec[s][i].v]>dis[s]+vec[s][i].w){
    55                     dis[vec[s][i].v]=dis[s]+vec[s][i].w;
    56                     cnt[vec[s][i].v]++;
    57                     if (cnt[vec[s][i].v]>=n)
    58                         return true; 
    59                     q.push(vec[s][i].v);
    60                     vis[s]=vis[vec[s][i].v]=false;
    61                 }                
    62             }
    63         }
    64     }
    65     return false;
    66 }
    67 int main(){
    68 
    69     int F;
    70     scanf("%d",&F);
    71     while (F--){
    72         init();
    73         if (spfa(1))
    74             printf("YES
    ");
    75         else
    76             printf("NO
    ");
    77     }
    78     return 0;
    79 } 
    POJ3259 AC代码

    P1144

     1 #include<iostream>
     2 #include<vector>
     3 #include<queue>
     4 #include<cstring>
     5 using namespace std;
     6 const int MAXN=1e6+3,Mod=100003;
     7 int n,m,ans[MAXN],cnt[MAXN];
     8 vector<int>vec[MAXN];
     9 void BFS(){
    10     ans[1]=0;
    11     cnt[1]=1;
    12     queue<int>q;
    13     while(!q.empty())
    14         q.pop();
    15     q.push(1);    
    16     while (!q.empty()){
    17         int res=q.front();
    18         q.pop();
    19         for (int i=0;i<vec[res].size();i++){    
    20             if (vec[res][i]!=1&&(ans[vec[res][i]]==0||ans[vec[res][i]]==ans[res]+1)){
    21                 if (ans[vec[res][i]]==0)
    22                     q.push(vec[res][i]);
    23                 cnt[vec[res][i]]=(cnt[vec[res][i]]+cnt[res])%Mod;    
    24                 ans[vec[res][i]]=ans[res]+1;                            
    25             }        
    26         }
    27     }
    28     return ;
    29 }
    30 int main()
    31 {
    32     int u,v;
    33     scanf("%d%d",&n,&m);
    34     for(int i=1;i<=m;i++){
    35         scanf("%d%d",&u,&v);
    36         vec[u].push_back(v);
    37         vec[v].push_back(u);
    38     }
    39     BFS();
    40     for (int i=1;i<=n;i++)
    41         printf("%d
    ",cnt[i]%Mod);
    42     return 0;
    43 }
    P1144 最短路计数

    五.堆优化后的 Dijkstra

      时间复杂度:O((n+m)logn)

      有些题目不存在负权边,但是出的数据会卡SPFA,这个时候又要回到Dijkstra

      

    P4779

     1 #include<iostream>
     2 #include<bits/stdc++.h>
     3 using namespace std;
     4 
     5 const int MAXN=1e5+10,MAXM=2e5+10,inf=0x7fffffff;
     6 struct Edge{
     7     int to,w,next;
     8 }e[MAXM];
     9 int cnt=0,head[MAXN],dis[MAXN];
    10 bool vis[MAXN];
    11 void Add(int u,int v,int w){
    12     cnt++;
    13     e[cnt].to=v;
    14     e[cnt].w=w;
    15     e[cnt].next=head[u];
    16     head[u]=cnt;
    17 } 
    18 struct Node{
    19     int u,dis;
    20     bool operator <(const Node &x) const
    21     {
    22         return x.dis<dis;
    23     }
    24 };
    25 std::priority_queue<Node> q;
    26 void dijkstra(int start){
    27     dis[start]=0;
    28     q.push((Node){start,0});
    29     while(!q.empty()){
    30         Node tmp=q.top();
    31         q.pop();
    32         int x=tmp.u,d=tmp.dis;
    33         if (vis[x])
    34             continue;
    35         vis[x]=true;
    36         for (int i=head[x];i;i=e[i].next){
    37             int to=e[i].to;
    38             if (dis[to]>dis[x]+e[i].w){
    39                 dis[to]=dis[x]+e[i].w;
    40                 if (!vis[to]){
    41                     q.push((Node){to,dis[to]});
    42                 }
    43             }
    44         }
    45     }
    46 }
    47 int main(){
    48     
    49     int n,m,start;
    50     scanf("%d%d%d",&n,&m,&start);
    51     for (int i=1;i<=n;i++)
    52         dis[i]=inf; 
    53     int u,v,w;
    54     for (int i=1;i<=m;i++){
    55         scanf("%d%d%d",&u,&v,&w);
    56         Add(u,v,w);
    57     }
    58     dijkstra(start);
    59     for (int i=1;i<=n;i++){
    60         cout<<dis[i]<<" ";
    61     }
    62     cout<<endl;
    63     return 0;
    64 }
    P4779 堆优化的Dijkstra

     六.A*算法

       可以轻松求到第k短路

  • 相关阅读:
    Biba模型简介
    Fragment 与 Activity 通信
    小米2S 连接Ubuntu Android Studio
    【转】Android 实现“再按一次退出程序”
    取消 EditText 自动聚焦弹出输入法界面
    为Android Studio 项目手动下载gradle
    【转】Java读取文件方法大全
    sudo: /etc/sudoers 的模式为 0551,应为 0440
    Win7 下硬盘安装Linux Mint 17
    Linux Versus Windows, Ubuntu/Mint V XP/Vista/7
  • 原文地址:https://www.cnblogs.com/q1204675546/p/11716043.html
Copyright © 2011-2022 走看看