最短路变短了【最短路】

题意:

题目链接
题解链接

分析:

  首先,在原图上以点 (1) 为起点跑一遍最短路,处理出 (dis1[i])
  然后,把所有边反向以点 (n) 为起点跑一遍最短路,处理出 (dis2[i])
  当把第 (i) 条边反向后,假设该边的为 (u o v),边权为 (c)。修改之后的图与原图相比,可能替代原来最短路变成新最短路的路径只有可能是 (1 o v o u o n)
因此,需要判断该条路径和原最短路的关系。
(dis1[v]+dis2[u]+c<dis1[n]) 时,表示最短路变短,否则没有。
证明:
对于该式子:

[dis1[v]+dis2[u]+c ]

  (dis2[u]) 为反向图时求的最短路,把边反向时对其值没有影响。(c) 的值也不变。但边 (u o v) 反转后,可能会对 (dis1[v]) 产生影响,只需要对 (dis1[v]) 进行讨论。
(dis1[v]) 并没有经过边 (u o v) 时,(dis1[v]) 并没有发生改变,可以直接用于判断。
(dis1[v]) 经过了边 (u o v) 时,那么当该边反向后,(dis1[v]^{'}geq dis1[v]),如果仍用 (dis1[v]) 来判断的话,这条新的路径的长度会比原来路径 (1 o u o v o n) 要多 (c),因此必然不可能,所以用 (dis1[v]) 仍然可以判断。

代码:

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<ll,int>P;
const ll inf=1e16;
const int N=1e5+5;
struct edge
{
    int u,v;
    ll w;
}e[N<<1];
vector<P>G[2][N];
priority_queue<P,vector<P>,greater<P> >que;
ll dis[2][N];
void read(int &x)
{
    x=0;
    int f=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    x*=f;
}
void dij(int s,int f,int n)
{
    while(!que.empty())
        que.pop();
    que.push(make_pair(0,s));
    for(int i=1;i<=n;i++)
        dis[f][i]=inf;
    dis[f][s]=0;
    while(!que.empty())
    {
        P now=que.top();
        que.pop();
        if(dis[f][now.second]<now.first)
            continue;
        for(int i=0;i<G[f][now.second].size();i++)
        {
            P tmp=G[f][now.second][i];
            if(dis[f][tmp.second]>dis[f][now.second]+tmp.first)
            {
                dis[f][tmp.second]=dis[f][now.second]+tmp.first;
                que.push(make_pair(dis[f][tmp.second],tmp.second));
            }
        }
    }
}
int main()
{
    int n,m,u,v,c,q,d;
    read(n),read(m);
    for(int i=1;i<=m;i++)
    {
        read(u),read(v),read(c);
        G[0][u].pb(make_pair(c,v));
        G[1][v].pb(make_pair(c,u));
        e[i].u=u;
        e[i].v=v;
        e[i].w=c;
    }
    dij(1,0,n);
    dij(n,1,n);
    read(q);
    while(q--)
    {
        read(d);
        if(dis[0][e[d].v]+dis[1][e[d].u]+e[d].w<dis[0][n])
            printf("YES
");
        else
            printf("NO
");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/1024-xzx/p/12682980.html