SDOI2009Elaxia的路线--想法+dijkstra

来源:互联网 发布:笔记本怎么用梯子 知乎 编辑:程序博客网 时间:2024/06/06 01:58

题意:给出一个无向图和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;}


1 0