(最短路+拓扑排序)[SDOI2009]Elaxia的路线

https://www.luogu.org/problemnew/show/P2149
最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间。
Elaxia和w
每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的前提下,一起走的时间尽可能的长。
现在已知的是Elaxia和w**所在的宿舍和实验室的编号以及学校的地图:地图上有N个路 口,M条路,经过每条路都需要一定的时间。 具体地说,就是要求无向图中,两对点间最短路的最长公共路径。

分析样例发现最长公共路径可以包括两个人不同方向同一条路即可。
从两个起点、终点跑四边spfa得到不同起点的dis数组用于判断某一边是否存在与最短路中,将x1->y1, x2->y2的最短路边加入到新的图中,在从新图中x1->y1拓扑排序,记录一个结果

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pa;
const int maxn = 1500 + 10;
const int INF = 0x3f3f3f3f;
struct node {
    int to, val;
    node(int _to, int _val) : to(_to), val(_val) {} 
    bool operator < (const node& x) const {
        return val > x.val;
    }   
};
int dis[6][maxn], tot, tot_, head[maxn], head_[maxn], cnt[maxn], dp[maxn], vis[maxn]; 
struct edge {
    int frm, to, val, nxt, im;
    edge() {}
    edge(int _frm, int _to, int _val, int _nxt) : frm(_frm), to(_to), val(_val), nxt(_nxt) {}
    edge(int _frm, int _to, int _val, int _nxt, int _x) : frm(_frm), to(_to), val(_val), nxt(_nxt), im(_x) {}
} E[maxn * maxn], E_[maxn * maxn];
void addEdge(int u, int v, int w) {
    E[++tot] = edge(u, v, w, head[u]);
    head[u] = tot;
}
void addEdge_(int u, int v, int w, int x) {
    E_[++tot_] = edge(u, v, w, head_[u], x);
    head_[u] = tot_;
}
void spfa(int cnt, int s) {
    priority_queue<node> q;
    q.push(node(s, 0));
    register int i;
    memset(dis[cnt], 1, sizeof(dis[cnt]));
    memset(vis, 0, sizeof(vis));
    dis[cnt][s] = 0;
    while(!q.empty()) {
        node x = q.top();
        q.pop();
        vis[x.to] = 1;
        for (i = head[x.to]; i; i = E[i].nxt) {
            if(vis[E[i].to]) continue;
            if(dis[cnt][E[i].to] > dis[cnt][x.to] + E[i].val) {
                dis[cnt][E[i].to] = dis[cnt][x.to] + E[i].val;
                q.push(node(E[i].to, dis[cnt][E[i].to]));
            }
        }
    }
}
int main()
{
    int n, m, x1, y1, x2, y2, u, v, w;
    scanf("%d%d", &n, &m);
    scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    register int i;
    for (i = 0; i < m; i++) {
        scanf("%d%d%d", &u, &v, &w);
        addEdge(u, v, w);
        addEdge(v, u, w);
    }
    spfa(1, x1);
    spfa(2, y1);
    spfa(3, x2);
    spfa(4, y2);
    for (i = tot; i > 0; i--) {
        u = E[i].frm, v = E[i].to, w = E[i].val;
        if (dis[1][u] + w + dis[2][v] == dis[1][y1]) {
            if(dis[3][u] + w + dis[4][v] == dis[3][y2] || dis[4][u] + w + dis[3][v] == dis[3][y2])
                addEdge_(u, v, w, 1);
            else
                addEdge_(u, v, w, 0);
            cnt[v]++; //入度
        }
    }
    //topo
    queue<int> q;
    q.push(x1);
    while(!q.empty()) {
        int x = q.front();
        q.pop();
        for (i = head_[x]; i; i = E_[i].nxt) {
            if(!(--cnt[E_[i].to]))
                q.push(E_[i].to);
            dp[E_[i].to] = max(dp[E_[i].to], dp[E_[i].frm] + E_[i].val * E_[i].im);
        }
    }
    printf("%d\n", dp[y1]);
    // system("pause");
}

猜你喜欢

转载自blog.csdn.net/weixin_40588429/article/details/84106191
今日推荐