Codeforces 567E President and Roads (用Dijkstra求最短路条数 + 强连通桥)

来源:互联网 发布:数据库备份类型 编辑:程序博客网 时间:2024/05/08 12:15

@(K ACMer) by 题解工厂


题意:

给你一个有向图,问你这条边是不是最短路必须经过的边.如果不是能不能通过减少它的长度(但必须边的长度大于0)来让它成为必须经过的边.


分析:

先谈,判断一个路径(u, v)是不是最短路上的路.显然如果u到起点的距离加上v到终点的距离,再加上(u,v)边的长度等于起点到终点的最短路长度,那么这个边就可能是最短路上的路,但是不一定就是,因为也可能存在和它等效的边.
那么如何判断最短路必须经过(u,v)这条边否呢?

首先这条边必须是可能的最短路上的路径,这就需要满足长度的关系.
然后只需要满足起点到u的最短路条数a乘以v到终点的最短路条数b等于起点到终点的最短路条数即可.
要完成以上两个关于路径长度和路径数的判断,都需要用dijkstra算法,分别从起点和终点建图,且建图的时候,不只是要有最短路长度,还要有路径数.Dijkstra很天然的可以算出,从起点到该点的最短路条数,只需要看它被相同更新了多少次,没更新一次,就把它前驱节点的条数给它加上.

有了以上的方法,减少多少变为毕竟最短路的也就容易类比想到了.


Dijkstra算法的两个特点:

最短路条数:首先更据上面的内容,Dijstra算法不仅仅可以算最短路长度,还可以算,最短路条数.
任意点到起点最短路:跑了一遍Dijkstra算法之后,会得到一个d[]数组,这是起点到每个点的最短距离.我们可以利用这一特性,可以计算每一个点到起点的最短距离(在无向图中,显然就等于起点到每个点的最短距离,有向图就不同了).方法如下:

以该有向图建立一个反图(反图就是,把有向图中每一个边都反向).然后跑一次Dijkstra,就得到反图中起点到任意点的最短距离,但其实在原图中把这条路径反过来,就是起任意点到起点的最短距离.


Code:

#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <set>#include <map>#include <vector>#include <queue>#include <iterator>#include <cmath>#include <cstring>#include <cstdlib>using namespace std;typedef long long LL;typedef pair<LL, LL> P;const LL  M = 200009;LL INF = 1000000000000LL;LL prime = 1044556773;LL V, E, s, e;struct edges{LL from, to, cost;};struct edge{LL to, cost;};vector<struct edge> G1[M], G2[M];vector<edges > g;struct dot{LL x, ways;}d1[M], d2[M];void input(void){    scanf("%I64d%I64d%I64d%I64d", &V, &E, &s, &e);    for (LL i = 0; i < E; i++) {        LL x, y, z;        scanf("%I64d%I64d%I64d", &x, &y, &z);        G1[x].push_back({y, z});        G2[y].push_back({x, z});        g.push_back({x, y, z});    }}void dijkstra1(LL s){    priority_queue<P, vector<P>, greater<P> > que;    for (LL i = 0; i  < V + 100; i++) d1[i].x = INF, d1[i].ways = 0;    d1[s].x = 0;    d1[s].ways = 1;    que.push(P(0, s));    while (!que.empty()) {        P p = que.top(); que.pop();        LL v = p.second;        if (d1[v].x < p.first) continue;        for (LL i = 0; i < G1[v].size(); i++) {            edge ed = G1[v][i];            if (d1[ed.to].x == d1[v].x + ed.cost ) {                d1[ed.to].ways = (d1[v].ways % prime + d1[ed.to].ways % prime) % prime;            } else            if (d1[ed.to].x > d1[v].x + ed.cost){                d1[ed.to].x = d1[v].x + ed.cost;                d1[ed.to].ways = d1[v].ways;                que.push(P(d1[ed.to].x, ed.to));            }        }    }}void dijkstra2(LL s){    priority_queue<P, vector<P>, greater<P> > que;    for (LL i = V + 100; i  > 0; i--) d2[i].x = INF, d2[i].ways = 0;    d2[s].x = 0;    d2[s].ways = 1;    que.push(P(0, s));    while (!que.empty()) {        P p = que.top(); que.pop();        LL v = p.second;        if (d2[v].x < p.first) continue;        for (LL i = 0; i < G2[v].size(); i++) {            edge ed = G2[v][i];            if (d2[ed.to].x == d2[v].x + ed.cost) {                d2[ed.to].ways = (d2[v].ways % prime + d2[ed.to].ways % prime) % prime;            } else            if (d2[ed.to].x > d2[v].x + ed.cost){                d2[ed.to].x = d2[v].x + ed.cost;                d2[ed.to].ways = d2[v].ways;                que.push(P(d2[ed.to].x, ed.to));            }        }    }}int main(void){    input();    dijkstra1(s);    dijkstra2(e);    for (LL i = 0; i < g.size(); i++) {        LL sx = g[i].from, ex = g[i].to, y = g[i].cost;        if (d1[sx].x + d2[ex].x == d1[e].x - y && ((d1[sx].ways%prime) * (d2[ex].ways%prime))%prime == d1[e].ways % prime) {            printf("YES\n");        } else {            LL z = d1[e].x - d1[sx].x - d2[ex].x;            if (z - 1<= 0) printf("NO\n");            else {printf("CAN %I64d\n", y - z + 1);}        }    }    return 0;}
0 0
原创粉丝点击