poj 3255(次短路)

博客探讨了如何求解图中从顶点1到顶点n的次短路问题。通过分析,确定次短路是沿着最短路径在某点偏离后再返回,并且只偏离一次。文章提出了一种方法,先计算最短路径,然后枚举边找到恰比最短距离大的路径。此外,还提供了一个利用最短路和次短路思想的程序实现,虽然作者表示不太理解其工作原理,但运行效率有所提升。
摘要由CSDN通过智能技术生成

      题意:给出n个点,m条边,求从顶点1到顶点n的次短路。

      分析:首先可以知道,次短路应是在最短路的某个顶点处绕了出去,然后又回到最短路的某个顶点,而且只会绕一次(绕多次的距离肯定比绕一次的大)。再考虑次短路上的两个相邻点i和j,用d1[i]表示从源点1到i的最短距离,用d2[j]表示从j到汇点n的最短距离,那么当i和j在次短路与最短路重合的部分(即没绕出去的那部分)时,d[i]+w[i][j]+d[j]就是最短路的距离,当i或j有一个点处于绕出去的那部分时,d[i]+w[i][j]+d[j]就是次短距离。

      因此,我们可以先求出所有的d1[i]和d2[j],再枚举每一条边,求出恰比最短距离大的那个d[i]+w[i][j]+d[j],也即是所求解。

   代码如下:

#include <cstdio>
#include <stack>
#include <set>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <string>
#include <map>
#include <iomanip>
#include <cmath>
#define LL long long
#define ULL unsigned long long
#define SZ(x) (int)x.size()
#define Lowbit(x) ((x) & (-x))
#define MP(a, b) make_pair(a, b)
#define MS(arr, num) memset(arr, num, sizeof(arr))
#define PB push_back
#define F first
#define S second
#define ROP freopen("input.txt", "r", stdin);
#define MID(a, b) (a + ((b - a) >> 1))
#define LC rt << 1, l, mid
#define RC rt << 1|1, mid + 1, r
#define LRT rt << 1
#define RRT rt << 1|1
#define BitCount(x) __builtin_popcount(x)
#define BitCountll(x) __builtin_popcountll(x)
#define LeftPos(x) 32 - __builtin_clz(x) - 1
#define LeftPosll(x) 64 - __builtin_clzll(x) - 1
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
using namespace std;
const double eps = 1e-8;
const int MAXN = 300 + 10;
const int MOD = 1000007;
const int N=5010;
const int M=200010;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
typedef pair<int, int> pii;
int n,m,d1[N],d2[N];
int u[M],v[M],w[M],first[N],next[M];
bool vis[N];
void build()
{
    int i,j,t=m<<1;
    memset(first,-1,sizeof(first));
    for (i=0;i<t;i+=2){
        scanf("%d%d%d",u+i,v+i,w+i);
        next[i]=first[u[i]];
        first[u[i]]=i;
        u[i+1]=v[i]; v[i+1]=u[i]; w[i+1]=w[i];
        next[i+1]=first[u[i+1]];
        first[u[i+1]]=i+1;
    }
}
void dij(int s,int d[])
{
    int i,j;
    memset(vis,false,sizeof(vis));
    priority_queue<pii,vector<pii>,greater<pii> > q;
    for (i=1;i<=n;d[i++]=INF);
    d[s]=0;
    q.push(make_pair(d[s],s));
    while(!q.empty())
    {
        pii t=q.top(); q.pop();
        int pos=t.second, val=t.first;
        if (d[pos]<val) continue;
        vis[pos]=true;
        for (i=first[pos];i!=-1;i=next[i]) if (!vis[v[i]]) {
            if (d[v[i]]>d[pos]+w[i]){
                d[v[i]]=d[pos]+w[i];
                q.push(make_pair(d[v[i]],v[i]));
            }
        }
    }
}
int main()
{
    int i,j;
    while(~scanf("%d%d",&n,&m))
    {
        int a,b,c;
        build();
        dij(1,d1);
        dij(n,d2);
        int ans=INF;
        for (i=1;i<=n;i++)
            for (j=first[i];j!=-1;j=next[j])
        {
            int t=d1[u[j]]+w[j]+d2[v[j]];
            if (t>d1[n] && t<ans) ans=t;
        }
        cout<<ans<<endl;
    }
}




下面这个代码的思想是:到某个顶点v的次短路,要么是到另一个顶点u的次短路再加上u->v这条边,要么是到u的最短路再加上u->v这条边,因此所需要求的就是到所有顶点的最短路和次短路。于是在代码中不仅要记录下最短距离,还要记录下次短距离,并不断维护更新这两个距离(其实我也不太明白,照着模板敲的,程序运行时间比上一个代码要快一点~~~~~)

代码如下:

#include <cstdio>
#include <stack>
#include <set>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <string>
#include <map>
#include <iomanip>
#include <cmath>
#define LL long long
#define ULL unsigned long long
#define SZ(x) (int)x.size()
#define Lowbit(x) ((x) & (-x))
#define MP(a, b) make_pair(a, b)
#define MS(arr, num) memset(arr, num, sizeof(arr))
#define PB push_back
#define F first
#define S second
#define ROP freopen("input.txt", "r", stdin);
#define MID(a, b) (a + ((b - a) >> 1))
#define LC rt << 1, l, mid
#define RC rt << 1|1, mid + 1, r
#define LRT rt << 1
#define RRT rt << 1|1
#define BitCount(x) __builtin_popcount(x)
#define BitCountll(x) __builtin_popcountll(x)
#define LeftPos(x) 32 - __builtin_clz(x) - 1
#define LeftPosll(x) 64 - __builtin_clzll(x) - 1
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
using namespace std;
const int N=5010;
const int M=200010;
const double eps = 1e-8;
const int MAXN = 300 + 10;
const int MOD = 1000007;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
typedef pair<int, int> pii;
int n,m,v[M],u[M],w[M],first[N],next[M];
int d1[N],d2[N];
bool vis[N];
void addedge(int a,int b,int c,int i)
{
    u[i]=a; v[i]=b; w[i]=c;
    next[i]=first[a];
    first[a]=i;
}
void build()
{
    int i,j,a,b,c,t=m<<1;
    memset(first,-1,sizeof(first));
    memset(vis,false,sizeof(vis));
    for (i=0;i<t;i+=2){
        scanf("%d%d%d",&a,&b,&c);
        addedge(a,b,c,i);
        addedge(b,a,c,i+1);
    }
}
void dij(int s)
{
    int i,j;
    priority_queue<pii,vector<pii>,greater<pii> > q;
    for (i=1;i<=n;d1[i]=d2[i]=INF,i++);
    d1[s]=0;
    q.push(make_pair(d1[s],s));
    while(!q.empty())
    {
        pii t=q.top(); q.pop();
        int val=t.first ,pos=t.second,r;
        if (d2[pos]<val) continue;
        //vis[pos]=true;
        for (i=first[pos];i!=-1;i=next[i])  {
            r=val+w[i];
            if (d1[v[i]]>r){
                swap(d1[v[i]],r);
                q.push(make_pair(d1[v[i]],v[i]));
            }
            if (d2[v[i]]>r && d1[v[i]]<r){
                d2[v[i]]=r;
                q.push(make_pair(d2[v[i]],v[i]));
            }
        }
    }
}
int main()
{
    int i,j;
    while(~scanf("%d%d",&n,&m))
    {
        build();
        dij(1);
       // for (i=1;i<=n;cout<<d1[i++]<<" "); cout<<endl;
        cout<<d2[n]<<endl;
    }
}


























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值