Roadblocks POJ 3255 SPFA

Description 传送门:http://poj.org/problem?id=3255

Bessie has moved to a small farm and sometimes enjoys returning to visit one of her best friends. She does not want to get to her old home too quickly, because she likes the scenery along the way. She has decided to take the second-shortest rather than the shortest path. She knows there must be some second-shortest path.

The countryside consists of R (1 ≤ R ≤ 100,000) bidirectional roads, each linking two of the N (1 ≤ N ≤ 5000) intersections, conveniently numbered 1..N. Bessie starts at intersection 1, and her friend (the destination) is at intersection N.

The second-shortest path may share roads with any of the shortest paths, and it may backtrack i.e., use the same road or intersection more than once. The second-shortest path is the shortest path whose length is longer than the shortest path(s) (i.e., if two or more shortest paths exist, the second-shortest path is the one whose length is longer than those but no longer than any other path).

Input
Line 1: Two space-separated integers: N and R
Lines 2..R+1: Each line contains three space-separated integers: A, B, and D that describe a road that connects intersections A and B and has length D (1 ≤ D ≤ 5000)

Output
Line 1: The length of the second shortest path between node 1 and node N

Sample Input

4 4
1 2 100
2 4 200
2 3 250
3 4 100

Sample Output

450


求最短距离的变形
用SPFA作为模板,考虑所有的最小值产生情况
Ps: dis[i:记录节点1到节点i的最短距离;seDis[i]记录节点1到结点i的次短距离
首先,对于图中除起点外任意一点i,当dis[i]更新时,则原来存与dis数组中的值变为到节点i的次短距离。如果在松弛操作(dis[edge finish node] < dis[edge star node]+edge len)中,没有更新dis[i],也有可能是次短距离。如果在松弛操作中,与最优值相同(dis[edge finish node] = dis[edge star node]+edge len),此时要考虑是否用次短距离更新(seDis[edge finish node] > seDis[edge star node]+edge len ?)。最后考虑特判,只有两个点一条边的情况,这时候记与终点相连边中的最小长度(minN),输出min(dis[N]+minN*2,seDis[N])。


#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
struct edge{
    int star,finish;
    int val;
    edge* pre;
    edge(){};
    edge(int s,int f,int v):star(s),finish(f),val(v){};
};
struct adjList{
    edge* p;
    adjList():p(NULL){};
};

int N,R;
int dis[10240];
int seDis[10240];
queue<int> Q;
adjList preHead[10240];
void show();
int main(){
    scanf("%d %d",&N,&R);
    for(register int i=1;i<=N;i++)
        dis[i]=INF,seDis[i]=INF;
    dis[1]=0,seDis[1]=0;
    int star,finish,val;
    int minN=INF;
    for(register int i=0;i<R;i++){
        scanf("%d %d %d",&star,&finish,&val);
        if(star==N||finish==N)
            minN=min(minN,val);
        edge* e=new edge(star,finish,val);
        e->pre=preHead[star].p;
        preHead[star].p=e;
        e=new edge(finish,star,val);
        e->pre=preHead[finish].p;
        preHead[finish].p=e;
    }
    Q.push(1);
    int now;
    while(!Q.empty()){
        now=Q.front();
        Q.pop();
        edge* next=preHead[now].p;
        while(next){
            if(dis[next->finish]==dis[now]+next->val){
                if(seDis[next->finish]>seDis[now]+next->val){
                    seDis[next->finish]=seDis[now]+next->val;
                    Q.push(next->finish);
                }
                next=next->pre;
                continue;
            }
            if(dis[next->finish]>dis[now]+next->val){
                seDis[next->finish]=dis[next->finish];
                dis[next->finish]=dis[now]+next->val;
                    Q.push(next->finish);

            }else{
                if(seDis[next->finish]>dis[now]+next->val){
                    seDis[next->finish]=dis[now]+next->val;
                        Q.push(next->finish);
                }
            }
            next=next->pre;
        }
    }
    printf("%d\n",min(seDis[N],dis[N]+2*minN));
    return 0;
}

可能的错误说明
1、如果在松弛操作中,更新值与最短距离相同时,选择跳过这条边。
9 11
1 2 5
1 3 4
1 4 3
2 5 7
3 6 6
3 7 8
5 8 1
4 7 7
6 8 6
7 8 2
8 9 1
14
发生错误的样例
访问节点9之前必然会确定到节点8的最短距离,因此,无论访问几次节点9,都不会更新节点9的次短距离。
2、使用辅助数组标记标记节点是否已经在队列中。
9 11
1 2 5
1 3 4
1 4 3
2 5 7
3 6 6
3 7 8
5 8 1
4 7 7
6 8 6
7 8 2
8 9 1
14
这里写图片描述
还是这组数据。如果使用辅助数组进行标记,则每个节点在队列中只出现一次,可能造成只更新最小值,未更新次小值,并且队列中后续节点不再与此节点连接,即后续操作中不在压入该节点。比如节点8


测试数据
8 14
1 2 5
1 4 10
1 3 6
2 5 4
2 4 6
3 4 7
3 6 8
4 5 7
4 8 5
4 6 5
5 8 5
6 8 2
1 7 10
7 8 1
12

2 1
1 2 1
3

4 3
1 2 2
2 3 1
3 4 4
9

5 4
1 2 4
2 3 3
3 4 2
4 5 1
12

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

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

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

猜你喜欢

转载自blog.csdn.net/white_156/article/details/82053307