[SDOI2009]Elaxia的路线

来源:互联网 发布:云南大学urp软件下载 编辑:程序博客网 时间:2024/05/16 04:37

最近,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;} 

附一篇写的非常棒的洛谷题解(最后一篇)