POJ_3255 Roadblocks(最短路)

题意:

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

思路:

首先注意到点的取值范围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 
#include 
#include 
#include 
#include 
#include 

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[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 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 
#include 
#include 
#include 
#include 
#include 

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 que;
int dis[MAX_V];
int dis1[MAX_V];
bool mark[MAX_V];
vector 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+dis1[u]) && (dis[tmp.to]


你可能感兴趣的:(图论)