bzoj1880: [Sdoi2009]Elaxia的路线

20 篇文章 0 订阅
4 篇文章 0 订阅

题面在这里

题意:

求一个无向图中,两个点对最短路的最长公共路径。
注意给出的x1,y1和x2,y2不一定是从x走到y,可以是y走到x。

做法:

首先无脑跑最短路QAQ..
事实上,我们要把以x1,y1,x2,y2为起点的最短路都跑出来。

然后对于一条边u,v,边权为w,假如dis[s-u]+dis[v-t]+w == dis[s-t],则u-v这条边是在s-t的最短路上的。
我们把同在x1-y1,x2-y2的最短路上的边取出来重新构图,在新图上跑一个拓扑求最长链即可。
当然由于可以从y走到x,所以再把x2,y2交换一下再做一次拓扑,取两次答案的最大值。

代码:

/*************************************************************
    Problem: bzoj 1880 [Sdoi2009]Elaxia的路线
    User: fengyuan
    Language: C++
    Result: Accepted
    Time: 1148 ms
    Memory: 54796 kb
    Submit_Time: 2018-01-24 17:07:19
*************************************************************/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cctype>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;

inline ll read() {
    char ch = getchar(); ll x = 0; int op = 1;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
    for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
    return x*op;
}
inline void write(ll a) {
    if(a < 0) putchar('-'), a = -a;
    if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 1510;
int n, m, ans, cnt, s1, s2, t1, t2;
int head[N], head2[N], dis[5][N], dp[N], in[N];
bool vis[N];
struct edge {
    int to, nxt, v;
    edge() {}
    edge(int x, int y, int z) { to = x, nxt = y, v = z; }
}e[N*N<<1];

inline void addedge(int x, int y, int z) { e[++ cnt] = edge(y, head[x], z); head[x] = cnt; }
inline void addedge2(int x, int y, int z) { e[++ cnt] = edge(y, head2[x], z); head2[x] = cnt; }
inline void spfa(int p, int s) {
    queue<int> q; q.push(s); dis[p][s] = 0; memset(vis, 0, sizeof vis); vis[s] = 1;
    while(!q.empty()) {
        int u = q.front(); q.pop(); vis[u] = 0;
        for(int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if(dis[p][v] > dis[p][u]+e[i].v) {
                dis[p][v] = dis[p][u]+e[i].v;
                if(!vis[v]) { vis[v] = 1; q.push(v); }
            }
        }
    }
}
inline void tp() {
    queue<int> q; memset(dp, 0, sizeof dp);
    for(int i = 1; i <= n; i ++) if(!in[i]) q.push(i);
    while(!q.empty()) {
        int u = q.front(); q.pop(); ans = max(ans, dp[u]);
        for(int i = head2[u]; i; i = e[i].nxt) {
            int v = e[i].to; in[v] --;
            dp[v] = max(dp[v], dp[u]+e[i].v);
            if(!in[v]) q.push(v);
        }
    }
}
int main() {
    n = read(), m = read(), s1 = read(), t1 = read(), s2 = read(), t2 = read();
    for(int i = 1; i <= m; i ++) {
        int x = read(), y = read(), z = read();
        addedge(x, y, z); addedge(y, x, z);
    } memset(dis, 0x3f, sizeof dis);
    spfa(0, s1); spfa(1, t1); spfa(2, s2); spfa(3, t2);
    for(int i = 1; i <= n; i ++)
        for(int j = head[i]; j; j = e[j].nxt) {
            int k = e[j].to;
            if(dis[0][i]+dis[1][k]+e[j].v == dis[0][t1] && dis[2][i]+dis[3][k]+e[j].v == dis[2][t2]) {
                addedge2(i, k, e[j].v); in[k] ++;
            }
        }
    tp();
    swap(dis[2], dis[3]); memset(head2, 0, sizeof head2); memset(in, 0, sizeof in);
    for(int i = 1; i <= n; i ++)
        for(int j = head[i]; j; j = e[j].nxt) {
            int k = e[j].to;
            if(dis[0][i]+dis[1][k]+e[j].v == dis[0][t1] && dis[2][i]+dis[3][k]+e[j].v == dis[2][s2]) {
                addedge2(i, k, e[j].v); in[k] ++;
            }
        }
    tp();
    write(ans); puts("");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值