• HDU


    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=2680

    题目大意,就是一个人可以从多个起点开始出发,看到终点的最短路是多少。。只有可以运用和hdu2066一样的思想,对于每个起点可以看成是跟最最开始的点之间有一条权值为0的边。可以把最开始的点记做0点。那这样就可以使用单源最短路了。之前都没有用过spfa,今天来运用了一下。

     

    算法大致流程是用一个队列来进行维护。初始时将源加入队列。每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。直到队列为空时算法结束。

    这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法

     

    总结一下,spfa就是在bellmanford的基础之上运用了一个队列来进行优化,思想就是如果这个点的最短距离被更新且他不在队列中就加入队列,如果在就不需要重复加入队列。。因为当他取出来的时候已经是最后一次被更新过的值了。这样就避免了多次重复的操作。。反观bellman-ford未优化的话,要对于每一条边进行n-1次的松弛操作,从而来试图更新每条边终点的最短距离,而spfa就直接从一开始的起点出发找出相邻的边,判断是否能更新,并判断是否要加入队列(已在队列中就不加),这样就减少了很多更新的次数。

    例题 hdu 2680 

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <vector>
     6 #include <queue>
     7 using namespace std;
     8 #define M 1009
     9 #define INF 0x3f3f3f3f
    10 struct edge
    11 {
    12     int to,w;//保存边的信息,包括边的终点以及权值
    13 };
    14 int dis[M];  //最短距离的估计值(当前该点的最短距离)
    15 bool inq[M]; //标记该点是否在队列之中
    16 vector<edge> g[M]; //利用一个vector保存,g[i]表示以i为起点的所有边的信息
    17 int n,m,ee;
    18 void spfa(int u)
    19 {
    20     for(int i = 0;i <= n;i++) //初始化
    21     {
    22         dis[i] = INF; //将估计值都初始化为INF
    23         inq[i] = false; //初始化为不在队列中
    24     }
    25     dis[u] = 0; //起点的估计值直接就是0
    26     inq[u] = true; //加入队列并进行标记
    27     queue<int> q;
    28     q.push(u);
    29     while(!q.empty())
    30     {
    31         u = q.front();
    32         inq[u] = false;
    33         q.pop();
    34         for(int i = 0;i < g[u].size();i++)
    35         {
    36             int v = g[u][i].to; //找出这条边对应的终点
    37             int w = g[u][i].w;  //这条边对应的权值
    38             if(dis[v] > dis[u]+w) //如果终点的最短距离比起点的最短距离加上这条边的权值那么就更新
    39             {
    40                 dis[v] = dis[u]+w;
    41                 if(!inq[v]) //如果v点的最短距离有所更新并且不在队列中,就将其加入队列。
    42                 {           //否则就不需要重复加入队列增加不必要的操作。
    43                     inq[v] = true;  //加入队列并标记
    44                     q.push(v);
    45                 }
    46             }
    47         }
    48     }
    49 }
    50 int main()
    51 {
    52     while(scanf("%d %d %d",&n,&m,&ee)==3)
    53     {
    54         for(int i = 0;i <= n;i++) //清空vector避免多kase相互影响
    55             g[i].clear();
    56         for(int i = 0;i < m;i++)
    57         {
    58             int a,b,c;
    59             scanf("%d %d %d",&a,&b,&c);
    60             edge e;
    61             e.to = b;e.w = c;
    62             g[a].push_back(e);
    63             //e.to = a;
    64             //g[b].push_back(e);  //题目中有说从a到b有这条路,并不是双向的。
    65         }
    66         int s;
    67         scanf("%d",&s);
    68         for(int i = 0;i < s;i++)
    69         {
    70             int a;
    71             scanf("%d",&a);
    72             edge e;
    73             e.to = a; e.w = 0;
    74             g[0].push_back(e); //将家里到起点的权值设为0
    75             //e.to = 0;
    76             //g[a].push_back(e);  //从起点到家里是否有路其实无关紧要,因为思考一下有路的话 起点到起点也是0,所以根本不影响结果
    77         }
    78         spfa(0);
    79         //printf("debug-----%d
    ",dis[ee]);
    80         if(dis[ee]==INF)
    81             printf("-1
    ");
    82         else
    83             printf("%d
    ",dis[ee]);
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    Content-Type 之 application/json 与 text/javascript
    利用 filter 机制 给 静态资源 url 加上时间戳,来防止js和css文件的缓存,利于开发调试
    Tomcat 启动报错:No default web.xml
    $.parseJson 在 firefox 下返回 null 的问题
    利用 spring bean 的属性 init-method 解决因为数据库连接没有初始化而导致首次点击页面超慢的问题
    spring项目的 context root 修改之后,导致 WebApplicationContext 初始化两次的解决方法
    proxool 连接池警告分析:appears to have started a thread named [HouseKeeper] but has failed to stop it
    Log4j 输出的日志中时间比系统时间少了8小时的解决方法,log4j日志文件重复输出
    itext 实现pdf打印数字上标和下标
    log4j 实现只输入我们指定包的日志
  • 原文地址:https://www.cnblogs.com/weiyuan/p/5697899.html
Copyright © 2020-2023  润新知