洛谷 P2149 [SDOI2009]Elaxia的路线(两个最短路的公共路径)

  • 题意: 求两对点间最短路的最长公共路径。
  • 思路: 一开始想求出两个最短路的路径,然后暴力求公共路径,发现最短路的路径并不是唯一的。要对s1,t1,s2,t2,求出单源最短路,对于一条边(u,v,w)能够成为s1到t1的最短路上的点,有(d[u][s1] + w + d[v][t1] == d[t1][s1]),即s1到u的距离加上边权和t1到v的距离等于t1到s1的距离.
    先通过这个条件构造出s1到t1的最短路新图,再在这个图上判断是否也为s2到t2的最短路(或t2到s2的最短路),最后在两个条件都满足的边构成的有向图上拓扑排序求最长链即为答案.
#include<bits/stdc++.h>
#define ll long long
using namespace std;
typedef  pair<int,int> pii;
const int N = 2000;
const int inf = 0x3f3f3f3f;
struct E{
    int u,v,w,next;
}edge[N*N*2];

vector<int> path1,path2;
int head[N],tot,head2[N];
int d[N][5],in[N],dis[N];
int n ,m;
void add(int u,int v,int w){
    edge[++tot] = (E){u,v,w,head[u]};   head[u] = tot;
}
void add2(int i){
    edge[++tot] = edge[i];  edge[tot].next = head2[edge[i].u];  head2[edge[i].u] = tot;
}
void dijkstra(int s,int t){
    for(int i=1;i<=n;++i)   d[i][t] = inf;
    static priority_queue<pii,vector<pii>,greater<pii> > que;
    d[s][t] = 0;   que.push(pii(0,s));
    while(que.size()){
        pii p = que.top();  que.pop();
        int u = p.second;
        if(d[u][t]<p.first)    continue;   
        for(int i=head[u];i;i=edge[i].next){
            int v = edge[i].v, w = edge[i].w;
            if(d[v][t]>d[u][t]+w){
                d[v][t] = d[u][t]+w;
                que.push(pii(d[v][t],v));
            }
        }
    }
}
void topo(){
    stack<int> st;
    for(int i=1;i<=n;++i){
        if(in[i]==0)    st.push(i),dis[i] = 0;
    }   
    int u,v;
    while(st.size()){
        u = st.top();   st.pop();
        for(int i=head2[u];i;i=edge[i].next){
            v = edge[i].v;
            in[v]--;
            dis[v] = max(dis[v],dis[u]+edge[i].w);
            if(in[v]==0)    st.push(v);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    int s1,t1,s2,t2;
    scanf("%d%d%d%d",&s1,&t1,&s2,&t2);
    int u,v,w;
    for(int i=1;i<=m;++i){
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    dijkstra(s1,1);
    dijkstra(t1,2);
    dijkstra(s2,3);
    dijkstra(t2,4);
    for(int i=1;i<=n;++i){             
        for(int j=head[i];j;j=edge[j].next){
            if(d[i][1] + edge[j].w + d[edge[j].v][2] == d[t1][1]    // s1 -> t1
                && d[i][3] + edge[j].w + d[edge[j].v][4] == d[t2][3])// s2 -> t2
                add2(j),in[edge[j].v]++;
        }
    }
    topo();
    int ans = *max_element(dis+1,dis+1+n);
    memset(head2,0,sizeof head2);
    memset(in,0,sizeof in);
    memset(dis,0,sizeof dis);
    for(int i=1;i<=n;++i){
        for(int j=head[i];j;j=edge[j].next){
            if(d[i][1] + edge[j].w + d[edge[j].v][2] == d[t1][1] // s1 -> t1
                && d[i][4] + edge[j].w + d[edge[j].v][3] == d[t2][3]) // t2 -> s2 方向相反也算公共路径
                add2(j),in[edge[j].v]++;
        }
    }
    topo();
    ans = max(ans,*max_element(dis+1,dis+1+n));
    printf("%d
",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/xxrlz/p/11619931.html