Elaxia的路线 SDOI2009 最短路

56 篇文章 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。

输出格式:


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

说明


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

Analysis


题意已经很粗暴了
首先要找到哪些边在最短路上,可以想到如果dis_to_st[i] + dis_to_ed[j] + w[i, j] = 最短路的话,这条边处在最短路上
为了求出这些距离我们把给出的四个点我们分别跑spfa一共是四次,再把共有的边连成一张新的图拓扑排序做递推, len[u]=max(len[v]+w,len[u])
就这样,写写停停中途打了两个小时fgo一个下午吧

Code


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#define debug puts("-----")
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define fill(x, t) memset(x, t, sizeof(x))
#define min(x, y) x<y?x:y
#define max(x, y) x>y?x:y
#define PI (acos(-1.0))
#define EPS (1e-8)
#define INF (1<<30)
#define ll long long
#define db double
#define ld long double
#define N 1501
#define E N * N / 2 + 1
#define MOD 100000007
#define L 255
using namespace std;
struct edge{int x, y, w, next;}e[E], g[E];
int inQueue[N], mark[E], dis1[N], dis2[N], ind[N], lsE[N], lsG[N], dp[N];
inline int read(){
    int x = 0, v = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-'){
            v = -1;
        }
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0'){
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    return x * v;
}
inline int addEdgeE(int &cnt, const int &x, const int &y, const int &w){
    e[++ cnt] = (edge){x, y, w, lsE[x]}; lsE[x] = cnt;
    return 0;
}
inline int addEdgeG(int &cnt, const int &x, const int &y, const int &w){
    g[++ cnt] = (edge){x, y, w, lsG[x]}; lsG[x] = cnt;
    ind[y] += 1;
    return 0;
}
inline int spfa1(const int &st, const int &ed){
    fill(inQueue, 0);
    inQueue[st] = 1;
    fill(dis1, 63);
    dis1[st] = 0;
    queue<int>q;
    q.push(st);
    while (!q.empty()){
        int now = q.front(); q.pop();
        for (int i = lsE[now]; i; i = e[i].next){
            if (dis1[now] + e[i].w < dis1[e[i].y]){
                dis1[e[i].y] = dis1[now] + e[i].w;
                if (!inQueue[e[i].y]){
                    inQueue[e[i].y] = 1;
                    q.push(e[i].y);
                }
            }
        }
        inQueue[now] = 0;
    }
    return dis1[ed];
}
inline int spfa2(const int &st, const int &ed){
    fill(inQueue, 0);
    inQueue[st] = 1;
    fill(dis2, 63);
    dis2[st] = 0;
    queue<int>q;
    q.push(st);
    while (!q.empty()){
        int now = q.front(); q.pop();
        for (int i = lsE[now]; i; i = e[i].next){
            if (dis2[now] + e[i].w < dis2[e[i].y]){
                dis2[e[i].y] = dis2[now] + e[i].w;
                if (!inQueue[e[i].y]){
                    inQueue[e[i].y] = 1;
                    q.push(e[i].y);
                }
            }
        }
        inQueue[now] = 0;
    }
    return dis2[ed];
}
int main(void){
    int n = read(), m = read();
    int st1 = read(), ed1 = read(), st2 = read(), ed2 = read();
    int edgeCntE = 0, edgeCntG = 0;
    rep(i, 1, m){
        int x = read(), y = read(), w = read();
        addEdgeE(edgeCntE, x, y, w);
        addEdgeE(edgeCntE, y, x, w);
    }
    int stpath1 = spfa1(st1, ed1) & spfa2(ed1, st1);
    // printf("%d\n", stpath1);
    rep(i, 1, edgeCntE){
        if (dis1[e[i].x] + dis2[e[i].y] + e[i].w == stpath1 || dis2[e[i].x] + dis1[e[i].y] + e[i].w == stpath1){
            mark[i] += 1;
        }
    }
    int stpath2 = spfa1(st2, ed2) & spfa2(ed2, st2);
    // printf("%d\n", stpath2);
    rep(i, 1, edgeCntE){
        if (dis1[e[i].x] + dis2[e[i].y] + e[i].w == stpath2 || dis2[e[i].x] + dis1[e[i].y] + e[i].w == stpath2){
            mark[i] += 1;
        }
    }
    rep(i, 1, edgeCntE){
        if (mark[i] == 2 && dis1[e[i].x] < dis1[e[i].y]){
            addEdgeG(edgeCntG, e[i].x, e[i].y, e[i].w);
            // printf("x = %d y = %d w = %d\n", e[i].x, e[i].y, e[i].w);
        }
    }
    queue<int>q;
    rep(i, 1, n){
        if (!ind[i]){
            q.push(i);
        }
    }
    int ans = 0;
    while (!q.empty()){
        int now = q.front(); q.pop();
        // printf("%d ", now);
        ans = max(ans, dp[now]);
        for (int i = lsG[now]; i; i = g[i].next){
            if (!-- ind[g[i].y]){
                q.push(g[i].y);
                dp[g[i].y] = max(dp[now] + g[i].w, dp[g[i].y]);
            }
        }
    }
    // printf("\n%d , %d\n", stpath1, stpath2);
    printf("%d\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值