正题
题目链接:https://www.luogu.com.cn/problem/P2149
题目大意
nnn个点mmm条边的一张无向图,给定两个起点和对应的终点。求两个最短路的最长公共距离
解题思路
首先要求是最短路,我们可以先跑一次第一个起点的SPFASPFASPFA,然后从终点开始dfsdfsdfs保留所有的最短路。
这样我们可以保证剩下的图中的边一定是最短路上的边,之后考虑如何求答案。
我们可以再从第二个起点开始再跑一次单源最短路,保留数组,之后对于一条边如果即是第一个最短路的又是第二个最短路上的话我们就可以用类似于SPFASPFASPFA的方法来更新答案
时间复杂度O(n2)O(n^2)O(n2)(SPFA通通n2n^2n2处置)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1600;
struct node{int to,next,w;bool flag;
}a[N*N];
int n,m,tot=1,ans;
int s1,s2,t1,t2;
int ls[N],f[N],g[N];
bool v[N],vis[N];
queue<int> q;
void addl(int x,int y,int w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;return;
}
void SPFA(int s){memset(f,0x3f,sizeof(f));memset(v,0,sizeof(v));q.push(s);v[s]=1;f[s]=0;while(!q.empty()){int x=q.front();q.pop();for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(f[x]+a[i].w<f[y]){f[y]=f[x]+a[i].w;if(!v[y]){v[y]=1;q.push(y);}}}v[x]=0;}return;
}
void dfs(int x){v[x]=1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(f[y]+a[i].w==f[x]){a[i].flag=a[i^1].flag=1;if(!v[y])dfs(y);}}return;
}
void get_ans(){q.push(t2);v[t2]=vis[t2]=1;while(!q.empty()){int x=q.front();q.pop();for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(f[y]+a[i].w==f[x]){if(a[i].flag&&g[x]+a[i].w>g[y]){g[y]=max(g[y],g[x]+a[i].w);ans=max(ans,g[y]);if(!v[y]){v[y]=1;q.push(y);}}if(!vis[y]){vis[y]=v[y]=1;q.push(y);}}}v[x]=0;}return;
}
int main()
{scanf("%d%d",&n,&m);scanf("%d%d%d%d",&s1,&t1,&s2,&t2);for(int i=1;i<=m;i++){int x,y,w;scanf("%d%d%d",&x,&y,&w);addl(x,y,w);addl(y,x,w);}SPFA(s1);dfs(t1);SPFA(s2);get_ans();printf("%d",ans);
}