题意:给出一个无向图和s1,t1,s2,t2,求出s1-t1和s2-t2的最短路,使得这两条路径的最大公共路径最长。
做法:因为两点间最短路可能不唯一,所以不能直接构造。
如果一条边u-v在s-t的最短路径中,那么d[s][u]+c[u][v]+d[v][t]=d[s][t]。
所以预处理以s1,t1,s2,t2为原点的最短路径,再找出对s1,t1和s2,t2都满足上面式子的边,然后删去其他边,再跑一遍拓扑排序就可以了。
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=1505,inf=0x3f3f3f3f;
int Begin[maxn],to[maxn*maxn*2],Next[maxn*maxn*2],c[maxn*maxn*2],e,n;
bool is_ok[maxn*maxn*2];
void add(int u,int v,int w){
to[++e]=v,Next[e]=Begin[u],Begin[u]=e,c[e]=w;
}
struct node{
int id,dis;
bool operator < (const node &A) const {
return dis>A.dis;
}
};
queue<int>q;
priority_queue<node>Q;
struct Dijkstra{
int num,d[maxn];
void dijkstra(){
Q.push((node){num,0});
for(int i=1;i<=n;i++)d[i]=inf;
d[num]=0;
while(!Q.empty()){
node u=Q.top();Q.pop();
if(u.dis>d[u.id])continue;
for(int i=Begin[u.id];i;i=Next[i]){
int v=to[i];
if(d[v]>u.dis+c[i]){
d[v]=u.dis+c[i];
Q.push((node){v,d[v]});
}
}
}
}
}p[4];
void gett(int k,int u,int v,int w,int &t,bool &flag){
int p1=p[k].d[u]+p[k+1].d[v];
int p2=p[k+1].d[u]+p[k].d[v];
if(p1<p2)t=p1+w,flag=0;
else t=p2+w,flag=1;
}
int val[maxn],deg[maxn];
int solve(){
int res=0;
for(int i=1;i<=n;i++)
if(!deg[i])q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=Begin[u];i;i=Next[i])
if(is_ok[i]){
int v=to[i];
if(val[v]<val[u]+c[i]){
val[v]=val[u]+c[i];
if(res<val[v])res=val[v];
}if(--deg[v]==0)q.push(v);
}
}
return res;
}
int main(){
int m,u,v,w;
scanf("%d%d",&n,&m);
for(int i=0;i<4;i++)
scanf("%d",&p[i].num);
while(m--){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
for(int i=0;i<4;i++)
p[i].dijkstra();
for(int i=1;i<=e;i+=2){
bool flag1,flag2;
int u=to[i+1],v=to[i],t1,t2;
gett(0,u,v,c[i],t1,flag1);
gett(2,u,v,c[i],t2,flag2);
if((t1==p[0].d[p[1].num])&&(t2==p[2].d[p[3].num])){
if(flag1==0)is_ok[i]=1,deg[v]++;
else is_ok[i+1]=1,deg[u]++;
}
}
printf("%d\n",solve());
return 0;
}
本文介绍了一种算法,用于解决在一个无向图中找到两条特定路径的最短路问题,同时确保这两条路径间的最大公共路径尽可能长。通过预处理最短路径并进行拓扑排序来实现。

被折叠的 条评论
为什么被折叠?



