POJ_3255 Roadblocks(最短路)

来源:互联网 发布:淘宝财务报表 编辑:程序博客网 时间:2024/05/24 22:42

题意:

找第二短的路。注意是严格的第二短,第二短一定是大于第一短的路径,并且路可以重复走。

思路:

首先注意到点的取值范围N(1-5000),要用邻接表去双向存储边表。

接下来考虑如何求第二短的路径,最好想的一个思路就是利用最短路的算法在维护最短距离的同时维护次短距离。另外设置一个dist1数组,当到达i点的最短路径更新时,将之前的最短距离存储到次短距离。在此注意设置dist[1] = 0时,dis1[1] = INF,到达起点的起始次短距离是INF。

另外一种方法是顺序求出最短路数组dist[],逆序求出最短路数组dist1[]。接下来遍历每一条边,对于某一边e(i,j),次短路一定等于dist[i]+e(i,j)+dist1[j],且不等于dist[N](最短路)。

因为对于边e(i,j)来说,假设该边不存在,则其他点的最短距离的性质是不变的,但是因为经过这条边(可能是重复经过),使得有了另外一条次短的路径。所以当我们在两边同时获得最短距离,同时枚举边时,就可以找到次短路径。

至于最短路的算法,SPFA或Dijkstra都可以选择,SPFA时间复杂度O(KE)(K<=2),Dijkstra时间复杂度O(E+VlgV),但是我的Dijkstra都TLE了。。。可能是测试数据的问题,但是SPFA感觉还是上手快一点。

代码实现:

方法一:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <vector>#include <queue>using namespace std;const int MAX_V = 5005;const int INF = 0x7ffffff;struct Edge{    int to;    int cost;    Edge(int to,int cost){        this->to = to;        this->cost = cost;    }};int V,R;int dis1[MAX_V];int dis2[MAX_V];bool mark[MAX_V];vector<Edge> edge[MAX_V];void SPFA(int v,int dis[]);int main(){    while( scanf("%d%d",&V,&R) != EOF ){        for( int i = 1; i <= V; i++ ){            dis1[i] = dis2[i] = INF;            edge[i].clear();        }        int a,b,c;        for( int i = 0; i < R; i++ ){            scanf("%d%d%d",&a,&b,&c);            edge[a].push_back(Edge(b,c));            edge[b].push_back(Edge(a,c));        }        SPFA(1,dis1);        SPFA(V,dis2);        int res = INF;        for( int i = 1; i <= V; i++ ){            int len = edge[i].size();            for( int j = 0; j < len; j++ ){                Edge tmp = edge[i][j];                int tt = dis1[i]+tmp.cost+dis2[tmp.to];                if( (tt!=dis1[V]) && (tt<res) ){                    res = tt;                }            }        }        printf("%d\n",res);    }}void SPFA(int v,int dis[]){    queue<int> que;    que.push(v);    dis[v] = 0;    memset(mark,false,sizeof(mark));    while( !que.empty() ){        v = que.front();        que.pop();        mark[v] = false;        int len = edge[v].size();        for( int i = 0; i < len; i++ ){            Edge tmp = edge[v][i];            if( dis[tmp.to] > dis[v]+tmp.cost ){                dis[tmp.to] = dis[v]+tmp.cost;                if( mark[tmp.to] == false ){                    que.push(tmp.to);                    mark[tmp.to] = true;                }            }        }    }    return ;}

方法二:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <queue>#include <vector>using namespace std;const int MAX_V = 5005;const int INF = 0x7ffffff;struct Edge{    int to;    int cost;    Edge(int to,int cost){        this->to = to;        this->cost = cost;    };};int V,R;queue<int> que;int dis[MAX_V];int dis1[MAX_V];bool mark[MAX_V];vector<Edge> edge[MAX_V];int main(){    while( scanf("%d%d",&V,&R) != EOF ){        for( int i = 1; i <= V; i++ ){            dis[i] = INF;            dis1[i] = INF;            edge[i].clear();            mark[i] = false;        }        int a,b,c;        for( int i = 0; i < R; i++ ){            scanf("%d%d%d",&a,&b,&c);            edge[a].push_back(Edge(b,c));            edge[b].push_back(Edge(a,c));        }        dis[1] = 0;        que.push(1);        mark[1] = true;        while( !que.empty() ){            int u = que.front();            que.pop();            mark[u] = false;            int len = edge[u].size();            for( int i = 0; i < len; i++ ){                Edge tmp = edge[u][i];                if( dis[tmp.to] > tmp.cost+dis[u] ){                    dis1[tmp.to] = dis[tmp.to];                    dis[tmp.to] = tmp.cost+dis[u];                    if( mark[tmp.to] == false ){                        que.push(tmp.to);                        mark[tmp.to] = true;                    }                }                if( (dis1[tmp.to]>tmp.cost+dis[u]) && (dis[tmp.to]<tmp.cost+dis[u]) ){                    dis1[tmp.to] = tmp.cost+dis[u];                    if( mark[tmp.to] == false ){                        que.push(tmp.to);                        mark[tmp.to] = true;                    }                }                //比起Dijkstra这里要多处理一下,因为SPFA不带cost入队列                //所以对于每一条边要把起点的次短距离也考虑上                if( (dis1[tmp.to]>tmp.cost+dis1[u]) && (dis[tmp.to]<tmp.cost+dis1[u]) ){                    dis1[tmp.to] = tmp.cost+dis1[u];                    if( mark[tmp.to] == false ){                        que.push(tmp.to);                        mark[tmp.to] = true;                    }                }            }        }        printf("%d\n",dis1[V]);    }    return 0;}


0 0
原创粉丝点击