zoukankan      html  css  js  c++  java
  • 最短路径—迪杰斯特拉算法入门

    来求一波最短路径

    首先先看看一道题(如果没学过的话就看看,学过了还看博客干嘛?)

    http://ybt.ssoier.cn:8088/problem_show.php?pid=1381

    对于没有学过的童鞋们来说,可能最先想到的是BFS,DP。

    没错以上两个确实是基础的求最短路径的方法,但对于大部分最短路径的题来说,这是不实用的。

    于是我们就要学习新的算法啦,(一脸无奈-_-!!!)。

    首先来说迪杰斯特拉算法,(又是名字为五个字的高逼格算法)

    算法思想:
    设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

    其中我们把取了的电称为白点,还没取的点称为蓝点。

    其实这其中也掺杂了动规的思想,

    但注意!迪杰斯特拉算法无法处理负边权的情况(不要问我为什么)。

    所以当题中说边权为负就别用了。

    看看图人脑模拟一下!

    先给出一个无向图

    用Dijkstra算法找出以A为起点的单源最短路径步骤如下

    来看看上面那道题的代码。

     1 #include<cstdio>
     2 #include<queue>
     3 #include<cstring>
     4 using namespace std;
     5 int f[2005][2005];
     6 bool f1[2005][2005];//记录边是否重复出现过。
     7 bool p[2005];//判断点有没有取过。
     8 int dis[2005];//记录每个点到起点的最短距离。
     9 const int maxx=999999999;
    10 int main()
    11 {
    12     memset(f1,false,sizeof(f1));
    13     memset(p,true,sizeof(p));
    14     int n,m;
    15     scanf("%d%d",&n,&m);
    16     for(int i=1;i<=n;i++)
    17     for(int j=1;j<=n;j++)
    18     f[i][j]=maxx;//先把每条边的长度赋一个较大的值,
    19                  //等同于先让所有点之间都不连通.
    20     for(int i=1;i<=m;i++)
    21     {
    22         int a,b,w;
    23         scanf("%d%d%d",&a,&b,&w);
    24         if(f1[a][b]==false)
    25         {
    26             f[a][b]=w;
    27             f[b][a]=w;
    28             f1[a][b]=true;
    29             f1[b][a]=true;
    30         }
    31         else
    32         {
    33             if(f[a][b]>w)
    34             f[a][b]=w;
    35         }
    36         //注意检查同一条边的权值是否出现过多次
    37         //如果出现过多次,按最小值计算。
    38     }
    39     for(int i=1;i<=n;i++)
    40     dis[i]=f[1][i];
    41     dis[1]=0;
    42     p[1]=false;
    43     for(int i=1;i<=n-1;i++)
    44     {
    45         int minn=maxx;
    46         int k=0;
    47         for(int j=1;j<=n;j++)
    48         {
    49             if(p[j]&&dis[j]<minn)
    50             {
    51                 minn=dis[j];
    52                 k=j;
    53             }
    54         }
    55         if(k==0)break;//如果没有找到点了,说明找完了。
    56         p[k]=false;
    57         for(int j=1;j<=n;j++)
    58         {
    59             if(dis[j]>dis[k]+f[k][j])
    60             dis[j]=dis[k]+f[k][j];
    61         }//更新每个点到起点的距离
    62     }
    63     if(dis[n]==maxx)
    64     printf("-1");
    65     else
    66     printf("%d",dis[n]);
    67     return 0;
    68 }

    总之迪杰斯特拉算法是一个贼实用的算法,相信在以后的比赛中会得以体现。

    来到2012年普及组的最后一题练练!

    https://www.luogu.org/problem/show?pid=1078

    代码如下(做之前先别看!仅供参考!)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int c[1005];
     6 int f[1005][1005];
     7 bool p[1005];
     8 int dis[1005];
     9 int mp[1005][1005];
    10 int maxx=999999999;
    11 int main()
    12 {
    13     memset(p,true,sizeof(p));
    14     int n,k1,m,s,e;
    15     scanf("%d%d%d%d%d",&n,&k1,&m,&s,&e);
    16     for(int i=1;i<=n;i++)
    17         scanf("%d",&c[i]);
    18     for(int i=1;i<=k1;i++)
    19         for(int j=1;j<=k1;j++)
    20         scanf("%d",&f[i][j]);
    21     for(int i=1;i<=n;i++)
    22     for(int j=1;j<=n;j++)
    23     mp[i][j]=maxx;
    24     for(int i=1;i<=m;i++)
    25     {
    26         int a,b,w;
    27         scanf("%d%d%d",&a,&b,&w);
    28         if(f[c[a]][c[b]]==0)
    29         mp[b][a]=w;
    30         if(f[c[b]][c[a]]==0)
    31         mp[a][b]=w;
    32     }
    33     for(int i=1;i<=n;i++)
    34     dis[i]=mp[s][i];
    35     dis[s]=0;
    36     p[s]=false;
    37     int minn,k;
    38     for(int i=1;i<=n-1;i++)
    39     {
    40         minn=maxx;
    41         k=0;
    42         for(int j=1;j<=n;j++)
    43         {
    44             if(p[j]&&dis[j]<minn)
    45             {
    46                 k=j;
    47                 minn=dis[j];
    48             }
    49         }
    50         if(k==0)break;
    51         p[k]=false;
    52         for(int j=1;j<=n;j++)
    53         {
    54             if(dis[k]+mp[k][j]<dis[j])
    55             dis[j]=dis[k]+mp[k][j];
    56         }
    57     }
    58     if(dis[e]==maxx)
    59     {
    60         printf("-1");return 0;
    61     }
    62     printf("%d",dis[e]);
    63     return 0;
    64 }
  • 相关阅读:
    shell 脚本3 (输出与流程控制)
    centos 添加sudo 权限
    rz安装
    centos 安装mysql
    linux删除文件未释放
    关于字符串String的编程。
    spring mvc 学习指南二
    spring mvc 学习指南一
    《 spring mvc 》学习计划
    关于jsp的总结
  • 原文地址:https://www.cnblogs.com/genius777/p/8470335.html
Copyright © 2011-2022 走看看