[SDOI2009]Elaxia的路线

10 篇文章 0 订阅
3 篇文章 0 订阅

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值