POJ Roadblocks

Roadblocks

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 19676   Accepted: 6904

Description

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: AB, 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

Hint

Two routes: 1 -> 2 -> 4 (length 100+200=300) and 1 -> 2 -> 3 -> 4 (length 100+250+100=450)

Source

USACO 2006 November Gold

下面是我自己的思路,从源点到达某个顶点u的次短路的更新方式有两种,一种是基于源点到顶点v(顶点u的邻接点)的最短路基础上进行更新,另一种是基于源点到顶点v(顶点u的邻接点)的次短路的基础上的更新。

所以可以先进行一次迪杰斯特拉算法,求出源点到其余各个点的最短路径权值,

#include<cstdio>
#include<iostream>
#include<vector>
#include<string.h>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>

using namespace std;

#define MAX 5005
#define INF 0x3fffffff

struct Edge
{
    int next;
    int weight;
};

vector<Edge> adj[2*MAX];
int d[MAX];
int pre[MAX];
int vis[MAX];
int vis0[MAX];
int mini;

void Djs(int s,int n)
{
    fill(d+1,d+n+1,INF);
    fill(pre+1,pre+n+1,INF);
    memset(vis,0,sizeof(vis));
    d[s]=0;
    while(1)
    {
        int u=-1;
        int mini=INF;
        for(int i=1;i<=n;i++)
        {
            if(d[i]<mini&&vis[i]==0)
            {
                mini=d[i];
                u=i;
            }
        }
        if(u==-1) break;
        vis[u]=1;
        for(int i=0;i<adj[u].size();i++)
        {
            int v=adj[u][i].next;
            int temp=d[u]+adj[u][i].weight;
            if(temp<d[v]&&vis[v]==0)
            {
                int temp0=d[v];
                d[v]=temp;
                temp=temp0;
            }
            if(temp<pre[v]&&temp>d[v])
            {
                pre[v]=temp;
            }
        }
    }
}

void Djs1(int n)
{
    memset(vis,0,sizeof(vis));
    while(1)
    {
        int u=-1;
        int mini=INF;
        for(int i=1;i<=n;i++)
        {
            if(pre[i]<mini&&vis[i]==0)
            {
                mini=d[i];
                u=i;
            }
        }
        if(u==-1) break;
        vis[u]=1;
        for(int i=0;i<adj[u].size();i++)
        {
            int v=adj[u][i].next;
            int temp=pre[u]+adj[u][i].weight;
            if(temp<pre[v]&&temp>d[v])
            {
                pre[v]=temp;
            }
        }
    }
}

int main()
{
    int N,R;
    scanf("%d %d",&N,&R);
    for(int i=0;i<R;i++)
    {
        int a,b,w;
        Edge t;
        scanf("%d %d %d",&a,&b,&w);
        t.next=b;
        t.weight=w;
        adj[a].push_back(t);
        t.next=a;
        adj[b].push_back(t);
    }
    Djs(1,N);//求出源点到其余各个点的最短路径大小
             //并用最短路径大小去更新源点到各个点次短路径
    Djs1(N);//用次短路经去更新次短路径
    printf("%d\n",pre[N]);
    return 0;
}
#define _CRT_SECURE_NO_WARNINGS
/*
7 10
0 1 5
0 2 2
1 2 4
1 3 2
2 3 6
2 4 10
3 5 1
4 5 3
4 6 5
5 6 9

4 4
0 1 100
1 3 200
1 2 250
2 3 100
*/
#include <iostream>
#include <functional>
#include <utility>
#include <queue>
#include <vector>
#include <cstdio>
using namespace std;

const int maxn = 5000 + 20;
const int INF = 9999999;
typedef pair<int, int> P;     //first-最短距离,second-顶点编号
struct edge
{
    int to, cost;
};

//输入
int N, R;             //N-点,R-边
vector<edge> G[maxn]; //图的邻接表表示

int dist[maxn];   //最短距离
int dist2[maxn];  //次短距离

void solve()
{
    priority_queue<P, vector<P>, greater<P> > que;
    fill(dist+1, dist + N+1, INF);
    fill(dist2+1, dist2 + N+1, INF);
    dist[1] = 0;
    que.push(P(0, 1));

    while (!que.empty())
    {
        P p = que.top(); que.pop();       //队列存放 (最短路和次短路)
        int v = p.second, d = p.first;
        if (dist2[v] < d) continue;       //如果次小的值小,跳过该值
        for (int i = 0; i < G[v].size(); i++) {
            edge &e = G[v][i];            //得到v的临边
            int d2 = d + e.cost;          //d2 = 已知最短或次短 + 临边权值
            if (dist[e.to] > d2) {        //如果未确定的最短路 > d2
                swap(dist[e.to], d2);
                que.push(P(dist[e.to], e.to));   //添加最短路
            }
            if (dist2[e.to] > d2 && dist[e.to] < d2) {
                dist2[e.to] = d2;                //说明d2是次大值
                que.push(P(dist2[e.to], e.to));  //添加次短路
            }
        }
    }
    printf("%d\n", dist2[N]);        //N位置的dist2即为
}

void input()
{
    int from, to, cost;
    edge tmp;
    for (int i = 0; i < R; i++) {
        cin >> from >> to >> cost;
        tmp.to = to; tmp.cost = cost;
        G[from].push_back(tmp);
        tmp.to = from;
        G[to].push_back(tmp);
    }
}

int main()
{
    cin >> N >> R;
    input();
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/chengsilin666/article/details/82079160