• 【dijkstra优化/次短路径】POJ3255-Roadblocks


    【题目大意】

    给出一张无向图,求出从源点到终点的次短边。

    【思路】

    先来谈谈Dijkstra的优化。对于每次寻找到当前为访问过的点中距离最短的那一个,运用优先队列进行优化,避免全部扫描,每更新一个点的最短距离就加入优先队列。有人会问,一个点如果已经处理完成了,那它还留在队列中怎么办?我们放入队列时将一个点那时的顶点编号和最短距离进行打包,如果取出该点时,它当前的最短距离小于该点标记的最短距离,说明该点已经取到最短距离,不进行操作。或者直接用一个vis数组来记录某一个点是否已经取到最短距离;其次的优化是用邻接表存储与每一个点相连的所有边,方便处理。

    这道题的做法和最短路径基本一致,唯一的不同点在于,在求出最短路径的情况下必须要保留下次短路径。对于Dijkstra判断中取出的每一个点,如果到它的最短距离大于当前该点的次短距离,则当前该点已经取到最短距离和次短距离,不进行操作,否则进行两次判断:如果小于最短边,则赋给最短变,并将最短边赋给次短边;或者如果大于最短变且小于次短边,则赋给次短边。两次完成之后均要加入队列。要注意几点:

    (1)由于是一张无向图,读入的时候必须正向、逆向分为两条边存储,所以实际有向边的数量为r的两倍,数组绝对不能开小!我就因为这个错拿了90分,还检查了三个小时后找到测试数据才意识到的...

    (2)初始化时,源点的短边初始化为0,源点的次短边必须初始化为INF,而不是0。比如下面这组数据:

    4 2
    1 2 100
    2 4 200
    答案应该是500,然而如果初始化为0则答案会输出700。因为500的结果是又1到2,在从2返回1,再到2,再到4,100+100+100+200=500得到的;如果次短边初始化为0,则次短路径不再返回源点,而是在2与4之间折返,会偏大。
    (3)53行绝对不能直接赋值,而是要swap!因为最短边被修改后,它的值是要留给次短边的。
    2015.09.06温习时候的补充
    (1)要注意
    if (head.len>secondis[head.num]) continue;的位置!我两次写的时候都把它放在了while(k!=-1)里面然后判断(d>secondis[v[k]])这是不对的!因为如果这个时候continue,k的值就无法改变,会导致死循环。
    (2)要注意优先队列默认是大顶堆,struct里面设置的时候前后大于小于号必须要相反才能设置成小顶堆!
    
    
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<queue>
     5 #include<cstdlib>
     6 using namespace std;
     7 const int INF=0x7fffffff;
     8 const int MAXN=100000+10;
     9 struct Rec
    10 {
    11     int num,len;
    12     bool operator < (const Rec &a) const
    13     {
    14         return len>a.len;
    15         /*优先队列强制设为以len为关键词的小顶堆*/
    16     }
    17 }; 
    18 int u[MAXN*2],v[MAXN*2],w[MAXN*2];
    19 /*依次表示每条道路的起点、终点和长度*/
    20 int dis[MAXN/2],secondis[MAXN/2];
    21 /*记录通往每一个路口的最短和次短距离*/
    22 int first[MAXN/2],next[MAXN*2];
    23 int n,r;
    24 
    25 void dijkstra()
    26 {
    27     priority_queue<Rec> que;
    28     
    29     for (int i=1;i<n;i++)
    30     {
    31          dis[i]=INF;
    32          secondis[i]=INF;
    33     }
    34     dis[0]=0;
    35     secondis[0]=INF;
    36     
    37     Rec temp;
    38     temp.len=0;temp.num=0;
    39     que.push(temp);
    40     
    41     while (!que.empty())
    42     {
    43         Rec head=que.top();
    44         que.pop();
    45         if (head.len>secondis[head.num]) continue;
    46         
    47         int k=first[head.num];
    48         while (k!=-1)
    49         {
    50             int d=head.len+w[k];
    51             if (dis[v[k]]>d)
    52             {
    53                 swap(dis[v[k]],d);
    54                 temp.len=dis[v[k]];temp.num=v[k];
    55                 que.push(temp);
    56             }
    57             if (dis[v[k]]<d && secondis[v[k]]>d)
    58             {
    59                 secondis[v[k]]=d;
    60                 temp.len=secondis[v[k]];temp.num=v[k];
    61                 que.push(temp);
    62             }
    63             k=next[k];
    64         }
    65     }
    66 }
    67 
    68 int main()
    69 {
    70     scanf("%d%d",&n,&r);
    71     memset(first,-1,sizeof(first));
    72     for (int i=0;i<r;i++)
    73     {
    74         scanf("%d%d%d",&u[i],&v[i],&w[i]);
    75         u[i]--;
    76         v[i]--;
    77         next[i]=first[u[i]];
    78         first[u[i]]=i;
    79         
    80         v[i+r]=u[i];
    81         u[i+r]=v[i];
    82         w[i+r]=w[i];
    83         next[i+r]=first[u[i+r]];
    84         first[u[i+r]]=i+r;
    85     }
    86     dijkstra();
    87     cout<<secondis[n-1]<<endl;
    88     return 0;
    89 }
    
    
    
    
  • 相关阅读:
    grep用法小结
    观察者模式
    类之间的关系
    Linux——makefile编写
    探索C++多态和实现机理
    进程间通信——管道
    C++继承引入的隐藏与重写
    Linux 文件读写操作与磁盘挂载
    xShell终端下中文乱码问题
    深入理解C++ new/delete, new []/delete[]动态内存管理
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/4706182.html
Copyright © 2020-2023  润新知