最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间。Elaxia和w每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的前提下,一起走的时间尽可能的长。 现在已知的是Elaxia和w**所在的宿舍和实验室的编号以及学校的地图:地图上有N个路 口,M条路,经过每条路都需要一定的时间。 具体地说,就是要求无向图中,两对点间最短路的最长公共路径。
输入格式:
第一行:两个整数N和M(含义如题目描述)。 第二行:四个整数x1、y1、x2、y2(1 ≤ x1 ≤ N,1 ≤ y1 ≤ N,1 ≤ x2 ≤ N,1 ≤ ≤ N),分别表示Elaxia的宿舍和实验室及w**的宿舍和实验室的标号(两对点分别 x1,y1和x2,y2)。 接下来M行:每行三个整数,u、v、l(1 ≤ u ≤ N,1 ≤ v ≤ N,1 ≤ l ≤ 10000),表 u和v之间有一条路,经过这条路所需要的时间为l。
输出格式:
一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)
最短路上求最长公共路径长,我们的想法是求出两个人的最短路上的边,找重叠部分最长的。
如何判断这条边是否在最短路上呢?正反跑最短路,加上那条边如果距离最短,就是最短路上的边。(和NOIP2017Park很像)。
最后我们按照一个人的最短路重构图,如果那条边是重叠部分则打上标记。
最短路显然是个DAG(同Park)。所以我们可以拓扑排序DP求出答案。
最后,千万记得!edge别开小了啊。。。。数据范围N是1500,无向完全图有2248500条边啊。。
cjr 是毒瘤出题人;mthq精通数据结构;pkl 是最强女选手;wyj才初三啊;ms默默AK;我没有学上:我们都有光明的前途。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e3+5;
const int N=3e6+5;
struct edge{
int to,next,w;
bool gg;
}e[N],e2[N];
int head[MAXN],cnt=0,num=0,rehead[MAXN];
inline void add(int u,int v,int w){e[++cnt]=(edge){v,head[u],w},head[u]=cnt;}
inline void addedge(int u,int v,int w,bool ok){e2[++num]=(edge){v,rehead[u],w,ok},rehead[u]=num;}
int n,m,x,y,xx,yy,di=0;
int dis[MAXN][4];// 0 正 1反 2 正 3反
bool vis[MAXN];
int inde[MAXN],rk[MAXN],f[MAXN];
queue<int>q;
void SPFA(int x,int times){
q.push(x);vis[x]=1;dis[x][times]=0;
while(q.size()){
int u=q.front();q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to,w=e[i].w;
if(dis[u][times]+w<dis[v][times]){
dis[v][times]=dis[u][times]+w;
if(!vis[v]){
vis[v]=1;q.push(v);
}
}
}
}
}
void readd(int base){
for(int u=1;u<=n;u++){
for(int i=head[u];i;i=e[i].next){
int v=e[i].to,w=e[i].w;
if(dis[u][0]+w+dis[v][1]==dis[y][0]){//要按照一个图的顺序来重建图,不然会不知道方向
inde[v]++;
if(dis[u][2]+w+dis[v][3]==dis[yy][2]||dis[v][2]+w+dis[u][3]==dis[xx][3])addedge(u,v,w,1);//只要有一个满足就是公共的
//因为题里迎面走来也是可以的
else addedge(u,v,w,0);
}
}
}
}
void topsort(){
q.push(x);
while(q.size()){
int u=q.front();q.pop();
rk[++di]=u;
for(int i=rehead[u];i;i=e2[i].next){
int v=e2[i].to,w=e2[i].w,l=e2[i].gg;
inde[v]--;
if(!inde[v]){
q.push(v);
}
// f[v]=max(f[v],f[u]+w*l);在这里DP也可以(因为是按照拓扑序的)
}
}
}
int dp(){
for(int i=1;i<=di;i++){
int u=rk[i];
for(int j=rehead[u];j;j=e2[j].next){
int v=e2[j].to,w=e2[j].w,l=e2[j].gg;
f[v]=max(f[v],f[u]+w*l);
}
}
return f[y];
}
int main(){
memset(dis,0x7f,sizeof(dis));
int tem1,tem2,tem3;
scanf("%d%d",&n,&m);
scanf("%d%d%d%d",&x,&y,&xx,&yy);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&tem1,&tem2,&tem3);
add(tem1,tem2,tem3);
add(tem2,tem1,tem3);
}
SPFA(x,0);SPFA(y,1);SPFA(xx,2);SPFA(yy,3);
readd(0);topsort();
printf("%d\n",dp());
return 0;
}
附一篇写的非常棒的洛谷题解(最后一篇)