=== ===
这里放传送门
=== ===
题解
首先我们可以知道如果把所有最短路上的边挑出来,再按照最短路中dis数组的递推关系给它加上方向的话这就是一个有向无环图。而如果把所有两个最短路的公共边挑出来的话,这个有向无环图中的最长链就是答案。并且判断一条边在最短路上的方式就是 dis[s→u]+w(u,v)+dis[u→t]=dis[s→t] 。并且因为这是无向图,所以求任意一个点到终点的距离只需要以终点为起点再跑一遍最短路就可以了。需要注意的问题就是公共路径从不同的方向经过也是可以的,所以需要把一对起点和终点倒过来再做一遍。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define clear(x)(memset(x,127,sizeof(x)))
#define inc(x)(x=(x%5000)+1)
using namespace std;
int n,m,p[2000],a[1000010],next[1000010],d1[2000],d2[2000],d3[2000],d4[2000],w[1000010];
int x1,y1,x2,y2,tot,cnt,point[2000],ans,L[2000],*f,*g,*F,*G;
struct edge{
int to,w,nxt;
}e[600010];
void add(int x,int y,int v){
tot++;a[tot]=y;w[tot]=v;next[tot]=p[x];p[x]=tot;
}
void addedge(int x,int y,int v){
cnt++;e[cnt].to=y;e[cnt].w=v;e[cnt].nxt=point[x];point[x]=cnt;
}
void SPFA(int s,int *d){
int q[5000],head,tail;
bool ext[3000];
memset(ext,false,sizeof(ext));
head=0;tail=1;q[tail]=s;d[s]=0;ext[s]=true;
while (head!=tail){
int u;inc(head);u=q[head];ext[u]=false;
for (int i=p[u];i!=0;i=next[i])
if (d[a[i]]>d[u]+w[i]){
d[a[i]]=d[u]+w[i];
if (ext[a[i]]==false){
inc(tail);q[tail]=a[i];ext[a[i]]=true;
}
}
}
}
bool init(int i,int num,int *ds,int *dt,int len){
return (ds[i]+dt[a[num]]+w[num]==len);
}
void find_long(int s1,int t1,int s2,int t2){
int q[5000],head,tail,in[3000];
memset(in,0,sizeof(in));
memset(point,0,sizeof(point));
memset(L,0,sizeof(L));
for (int i=1;i<=n;i++)
for (int j=p[i];j!=0;j=next[j])
if (init(i,j,f,g,f[t1])&&init(i,j,F,G,F[t2])){
addedge(i,a[j],w[j]);++in[a[j]];//加入有向边
}
head=tail=0;
for (int i=1;i<=n;i++)
if (in[i]==0) q[++tail]=i;
while (head!=tail){
int u;inc(head);u=q[head];
for (int i=point[u];i!=0;i=e[i].nxt){
int v=e[i].to;
L[v]=max(L[v],L[u]+e[i].w);
ans=max(ans,L[v]);//求最长链的同时更新答案
--in[v];
if (in[v]==0){inc(tail);q[tail]=v;}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
for (int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
clear(d1);clear(d2);clear(d3);clear(d4);
f=d1;g=d2;F=d3;G=d4;
SPFA(x1,f);SPFA(y1,g);SPFA(x2,F);SPFA(y2,G);
find_long(x1,y1,x2,y2);
swap(F,G);//交换起点和终点(x2,y2),交换最短路数组的指针
find_long(x1,y1,y2,x2);
printf("%d\n",ans);
return 0;
}
偏偏在最后出现的补充说明
通过最短路构造出的图啊树啊总是可以来做一些奇怪的事情?