BZOJ1880 [Sdoi2009]Elaxia的路线 【最短路 + dp】

题目

最近,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。 出出出格格格式式式::: 一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)。

输出格式

一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)

输入样例

9 10

1 6 7 8

1 2 1

2 5 2

2 3 3

3 4 2

3 9 5

4 5 3

4 6 4

4 7 2

5 8 1

7 9 1

输出样例

3

提示

对于30%的数据,N ≤ 100;
对于60%的数据,N ≤ 1000;
对于100%的数据,N ≤ 1500,输入数据保证没有重边和自环。

题解

最后的路径为公共的最短路,所以我们先将第一对点的所有最短路边建成一个新的拓扑图
然后就可以在新图上dp了
\(f[i]\)为第一对点走到\(i\)时的最大公共最短路长
显然\(f[i] = max{f[j] + edge.w}\)\(j\)\(i\)拓扑图中的前驱点且i-j这条边在第二对点的最短路上】

#include<iostream>
#include<cmath>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 1505,maxm = 3000005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
    return out * flag;
}
int h[maxn],ne = 2;
struct EDGE{int from,to,nxt,w,f;}ed[maxm];
inline void build(int u,int v,int w){
    ed[ne] = (EDGE){u,v,h[u],w}; h[u] = ne++;
    ed[ne] = (EDGE){v,u,h[v],w}; h[v] = ne++;
}
int n,m,S1,T1,S2,T2;
int d[4][maxn],vis[maxn];
struct node{int u,d;};
inline bool operator <(const node& a,const node& b){return a.d > b.d;}
priority_queue<node> q;
void dijkstra(int S,int p){
    for (int i = 1; i <= n; i++) d[p][i] = INF,vis[i] = false;
    d[p][S] = 0;
    node u;
    q.push((node){S,d[p][S]});
    while (!q.empty()){
        u = q.top(); q.pop();
        if (vis[u.u]) continue;
        vis[u.u] = true;
        Redge(u.u) if (!vis[to = ed[k].to] && d[p][to] > d[p][u.u] + ed[k].w){
            d[p][to] = d[p][u.u] + ed[k].w;
            q.push((node){to,d[p][to]});
        }
    }
}
int de[maxn],f[maxn];
queue<int> Q;
void solve(){
    dijkstra(S1,0); dijkstra(T1,1);
    dijkstra(S2,2); dijkstra(T2,3);
    for (int k = 2; k < ne; k++)
        if (d[0][ed[k].from] + ed[k].w + d[1][ed[k].to] == d[0][T1])
            ed[k].f = true,de[ed[k].to]++;
    Q.push(S1);
    int u;
    while (!Q.empty()){
        u = Q.front(); Q.pop();
        Redge(u) if (ed[k].f){
            if (d[2][u] + ed[k].w + d[3][to = ed[k].to] == d[2][T2] || d[3][u] + ed[k].w + d[2][to = ed[k].to] == d[2][T2])
                f[to] = max(f[to],f[u] + ed[k].w);
            if (!(--de[to])) Q.push(to);
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) ans = max(ans,f[i]);
    printf("%d\n",ans);
}
int main(){
    n = read(); m = read();
    S1 = read(); T1 = read(); S2 = read(); T2 = read();
    int a,b,w;
    for (int i = 1; i <= m; i++){
        a = read(); b = read(); w = read();
        build(a,b,w);
    }
    solve();
    return 0;
}

转载于:https://www.cnblogs.com/Mychael/p/8474300.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值