码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 4283 魔法少女伊莉雅 - 最短路

时间:2018-03-17 22:07:54      阅读:271      评论:0      收藏:0      [点我收藏+]

标签:size   指定   nod   boolean   起点   pad   namespace   space   bsp   

题目传送门

  需要高级权限的快速通道

题目大意

  给定一个$n$个点$m$条边的带正权无向图。要求找一条路径满足:

  • 它是一条简单路径
  • 它是一条严格次短路
  • 对于任何一条可能存在于最短路上的边,不能包含它的反向边。

  不存在这条路径输出-1。

  神题orz...orz....orz....良心的最短路性质题,涵盖了大部分最短路径树和最短路径图上的常用性质。

  直觉是最短路上随意判一判就好了。然后全WA了,qwq。。

  然后开始讲正题。

  将$d\left(u, v \right )$记为点$u$到点$v$的最短路的长度
  记$d_{s}\left(x \right ) = d\left(s, x \right ), d_{t}\left(x \right ) = d\left(x, t \right )$。

  最短路径图是$s$到$t$的所有最短路径的并集。

  举个例子有助于说明:

  技术分享图片

  左边为原图,右边为最短路径图。

注意 最短路径图是一个有向图。

  这里将原图记为$G = (V, E)$,最短路径图记为$G* = (V*, E*)$。

最短路径图的基本性质I(定义1.1) 对于任意$e \in E*$,若$e = (u, v)$,那么$d_{s}(u) + w(e) + d_{t}(v) = d(s, t)$。

  显然最短路径图一定是一个DAG。

  然后继续讨论最短路径图上的性质。

最短路径图的基本性质II(定理1.1) 对于任意$x \in V*$,那么有$d_{s}(x) + d_{t}(x) = d(s, t)$。

  证明 如果$s = x$,那么结论显然成立。

  现在考虑$s \neq x$的情况。暂时记$L = d(s, t)$

  由最短路径图的定义可知$d_{s}(x) \geqslant L - d_{t}(x)$。因为$x$不是起点,所以必然存在一个前驱$x‘$。

  根据基本性质I有$d_{s}(x‘) + w(x‘, x) + d_{t}(x) = L$。由$d_{s}(x)$的定义可知$d_{s}(x) \leqslant d_{s}(x‘) + w(x, x‘) = L - d_{t}(x)$。

  所以$d_{s}(x) = L - d_{t}(x)$。

  因此定理得证。

最短路径图的基本性质III(推论1.2) 对于$e = (x, y) \in E*$,那么有$d_{s}(x) + w(x, y) = d_{s}(y)$。

  证明 根据定理1.1有$d_{s}(y) = d(s, t) - d_{t}(y)$。根据定义1.1有$d_{s}(x) + w(x, y) = d(s, t) - d_{t}(y)$。然后定理得证。

最短路径图的基本性质IV(推论1.3) 如果最短路径图中存在一条$x$到$y$的简单路径,那么$d_{s}(x) + l(P*(x, y)) + d_{t}(y) = L$。其中P*(x, y)表示一条在$G*$上的路径,l(P*(x, y))表示这条路径的长度。

  重复使用推论1.2可以得到$d_{s}(x) + l(P*(x, y)) = d_{s}(y)$。然后根据定理1.1易证。详细证明留给读者。

最短路径图的基本性质V(推论1.4) 最短路径图中一条$x$到$y$的简单路径,对应原图中一条$x$到$y$的最短路。

  有了推论1.3就可以使用反证法。详细证明留给读者。同时可以推出上面的$ l(P*(x, y)) = d(x, y)$。

定理1.5 若$x, y \in V*$,且满足$x \neq y, d_{s}(x) \leqslant d_{x}(y)$,那么在$G*$中$s$到$x$的最短路与$y$到$t$的最短路不相交。

  证明 根据最短路径图的定义(定义1.1)可知,$s$到$x$的过程中$d_{s}(x‘)$递增,$y$到$t$的过程中$d_{s}(y‘)$递增。又因为$x \neq y, d_{s}(x) \leqslant d_{x}(y)$,所以它们不相交。

  然后来讲一些约定吧。

  正向边:对于一条有向边$(u, v)$,它在$E*$中,那么我们称它为一条正向边。

  反向边:对于一条有向边$(u, v)$,如果$(v, u) \in E*$,那么我们称它为一条反向边。

  内部边:正向边和反向边统称为内部边。

  外部边:在$E$中,但不属于$E*$的边。

  现在来明确一下约定路径的符号。

  $P(u, v)$,表示一条$u$到$v$的路径。

  $P*(u, v)$,表示一条在$G*$中$u$到$v$的路径。

  $P(x, y) + Q(y, z)$,表示一条沿着路径$P$从$x$走到$y$的,然后沿着$Q$,从$y$走到$z$的路径。

  $P^{-1}(x, y)$,表示沿着路径$P$的反向边(不是上面的定义的反向边),从$y$到$x$的一条路径。

  $P^{0}(x‘, y‘)$,路径$P$上,一条$x‘$到$y‘$的子路径。

  $l(P)$,表示路径$P$的长度。

  设所求路径为$S$。

  外部路径:起点和终点在$G*$中,经过的变都是外部边的一条简单路径。称起点是这条路径的拐出点,终点是这条路径的回归点

定理2.1 路径$S$中存在至少1条外部路径。

  证明 如果不包含外部路径,那么路径$S$中的边都是正向边(因为不能走反向边)。由于$G*$是一个DAG,所以$l(S) = d(s, t)$,不符合题目要求。

定理2.2 路径$S$的包含一条外部路径的拐出点为$x$,回归点为$y$,那么有$d_{s}(x) \leqslant d_{s}(y)$。

  证明 假设结论不成立,那么有$d_{s}(x) > d_{s}(y)$$。

  设$S = P(s, x) + Q(x, y) + R(y, t)$。那么令$U = P*(s, y) + Q^{-1}(x, y) + R*(x, t)$。因为路径$Q$是一条简单路径,P*和R*都是由正向边组成,根据定理1..5可得P*与R*不相交。所以$U$是一条简单路径。

  又因为$U$包含了至少一条外部边,所以它不是最短路。因此是一条满足题目要求的路径。

  又因为$P*(s, y) < P*(s, x) \leqslant P(s, x), R*(x, t) < R*(y, t) \leqslant R(y, t), Q(x, y) = Q^{-1}(x, y)$,所以$l(U) < l(S)$。

  与$S$的最优性矛盾。

定理2.3 路径$S$恰好包含一条外部路径。

  证明 假设包含的外部路径数目不是一条。

  • 如果不包含外部路径,显然矛盾。
  • 如果包含超过一条外部路径,设$S = P*(s, x) + Q(x, y) + R(y, t)$,令$U = P*(s, x) + Q(x, y) + R*(y, t)$,其中$Q(x, y)$是一条外部路径。
    根据定理1.5易证$U$是一条简单路径,根据最短路径图的定义有$R*(y, t) < R(y, t)$,因此$l(U) < l(S)$,与$S$的最优性矛盾。

  然后约定$S$的拐出点为$S$包含的外部路径的拐出点,它的回归点为它包含的外部路径的回归点。

  接下来看一看有关最短路径树的性质。

定义3.1 定义一棵以$p$为根的最短路径树$T_{p} = (V, E_{T})$是原图中以$p$为根的一棵有向路径生成树。其中一条边$e(v, u)$满足$d(u, p) + w(e) = d(v, p)$。

  由于下面只会用到$T_{t}$,因此,以下可能会直接将它简记$T$。

注意 

  1. 这里的最短路径树是一个有向图。
  2. 所有有向边都指向根节点。
  3. 一张无向图的最短路径图唯一,但指定点的最短路径生成树可能不唯一。

  然后再来定义定义子树。

定义3.2  在以$p$为根的最短路径生成树中:

点$x$的子树,在$T_{p}$点$x$断掉点$x$的唯一一条出边后,剩下的以$x$为根的树是点$x$的子树。记为$T_{p}(x)$。

点$x$的真子树,点$x$的真子树是$T_{p}(x)$的一个子图。在$T_{p}(x)$中,存在于点$x$的真子树的点,当且仅当它到$x$的路径上不经过除了$x$以外的任何属于$G*$的点。也就是说一个不是$x$的点,但属于$G*$,一定不存在于$x$的真子树中。记为$T*_{p}(x)$。

  真子树的定义可能不是很好理解(再加上我语文不好),那么来举个栗子:

技术分享图片

  在第三幅图之后,边权都被省略。在第四幅图和第五幅图中间橙色点标出的是在$G*$中的点。

  下面有一个关于真子树的很基本的性质。

定理3.1 对于任意$x,y \in G*$,都有$T*(x)\cap T*(y) = \varnothing $。

  根据真子树的定义易证。

  接下来再来约定一个记号。

  $P_{T}(x, y)$,在树$T_{t}$中,一条$x$到$y$的路径。

最短路径树中的基本性质(定理3.2  在最短路径树$T_{t}$中,任意一个点$x$到其祖先$y$的一条简单路径,对应原图中一条$x$到$y$的最短路。

  证明 易证当$y = t$时结论成立。

  考虑$y \neq t$的情况。

  仍然假设不是最短路。那么存在一条更优的路径的从$x$到$y$,然后到$t$的路径。与$T_{t}$的定义矛盾。

  因此定理得证。

  注意到如果将这条路径反向,可以对应$y$到$x$在原图中的一条最短路。

定义3.3 在$T$中,$x$的真祖先是在路径$P_{T}(x, t)$中,离$x$最近的一个在$G*$中的点。将它记作$prt(x)$。

  换一个说法就是沿着$x$向它的出边走,直到遇到一个在$G*$中的点。注意,它可能是$x$也可能是$t$。

  设$S$的拐出点为$x$,回归点为$z$,显然$x \in T*(x), z \in T*(z)$,根据定理3.1,那么$T*(x)$和$T*(z)$不存在交集。所以在$S$上必然存在一条外部边$(w, w‘)$使得$w \in T*(x)$,且$S^{0}(w‘, z)$中的各点均不在$T*(x)$中。有一个很显然的事实是$prt(w) = x$。

定理3.3 $d_{s}(x) \leqslant d_{s}(prt(w‘))$。

注意 以下证明非常繁琐,请先喝口水再继续阅读。

  证明 仍然假设结论不成立。那么有$d_{s}(x) > d_{s}(prt(w‘))$。所以$d_{t}(x) < d_{t}(prt(w‘))$。根据定理2.2有$d_{s}(x) <= d_{s}(z)$,因此$d_{s}(prt(w‘)) < d_{s}(z)$,所以$prt(w‘) \neq z$。根据定理3.1,可知,必然存在一条边$(y, y‘)$使得$y \in T*(prt(w‘))$且$S^{0}(y‘, z)$中的各点均不在$T*(prt(w‘))$。显然$prt(w‘) = prt(y)$。

技术分享图片

  令$Q = P*(s, prt(w‘)), R = P_{T}(prt(w‘), y), P = Q + R + S^{0}(y, t)$(见下图)。

技术分享图片

  可以证明$R$实际上是在$T*(prt(w‘))$中。假设路径上经过了其它的在$G*$中的点,那么可知$prt(y)$不等于$prt(w‘)$,矛盾。

  因为$d_{s}(prt(w‘))< d_{s}(z)$,根据定理1.5可知$Q$不与$S^{0}(z, t)$相交,又因为$R$在$T*(prt(w‘))$中,所以经过的边都是外部边,所以$P$中的内部边不相交。又因为$S^{0}(y‘. z)$是一条外部的简单路径,且不在$T*(prt(w‘))$。所以路径$P$中的外部边不相交。因此路径$P$是一条简单路径。(注意:这里的相交指的是存在环,而不是边与边存在公共点。)

  又因为$P$包含了至少一条外部边,所以$P$是一条满足要求的路径(除了严格次短)。

  因为$S$是所求路径,所以有:

$l(S) \leqslant l(P)$

$l(S^{0}(s, x)) + l(S^{0}(x, y)) + l(S^{0}(y, t)) \leqslant l(Q) + l(R) + l(S^{0}(y, t))$

$l(S^{0}(s, x)) + l(S^{0}(x, y)) \leqslant l(Q) + l(R)$

$d_{s}(x) + l(S^{0}(x, y)) \leqslant d_{s}(prt(w‘)) + l(R)$(推论1.4)

  又因为$prt(w‘) < d_{s}(x)$,所以$l(S^{0}(x, y)) < l(R)$。

  令$U = S^{0}(x, y)^{-1} + P*(x, t)$。那么有:

$l(U) = l(S^{0}(x, y)^{-1}) + l(P*(x, y))\\=l(S^{0}(x,y)) + d_{t}(x)\\<l(R) + d_{t}(prt(w‘))\\=l(R^{-1}) + d_{t}(prt(w‘))\\=l(P_{t}(y,t))$

  但是$U$经过了至少一条外部边,所以有$l(U) > l(P_{T}(y, t)) = d_{t}(y)$。但是刚刚却推出了与之矛盾的式子。

  所以假设不成立,定理得证:$d_{s}(x) \leqslant(prt(w‘))$。

  这是最后一个定理:

定理3.4 必然存在一个满足所有条件的路径S*,满足

$S* = P_{T}(s, w) + (w, w‘) + P_{T}(w‘, t)$

其中$(w, w‘)$是定理3.3中涉及到的一条边。

  证明 令$Q = P_{T}(s, w), R = P_{T}(w‘, t)$,根据定理3.1易证$S*$的外部边不相交,根据定理3.3和定理1.5易证$S*$的内部边不会相交。又因为$(w, w‘)$一定是一条外部边。所以$S*$是一条简单路径但不是最短路径。

  因为$S$中包含至少一条非树边,然后用反证法易证存在一个$S*$是满足题目所有要求的路径(除非原问题不存在解)。

  于是定理3.4创造了无限可能。

  我们只需要枚举一条非内部边,非树边$e(x, y)$,且满足$prt(x) \neq prt(y)$且$prt(x) \leqslant prt(y)$,然后用$d_{s}(x) + w(e) + d_{t}(y)$去更新答案即可。

  虽然证明很复杂,但是算法却异常简单。

  (终于可以完结撒花了,感觉像是写了3小时+的论文)

Code

  1 /**
  2  * bzoj
  3  * Problem#4283
  4  * Accepted
  5  * Time: 2720ms
  6  * Memory: 31172k
  7  */ 
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 typedef bool boolean;
 11 
 12 typedef class Edge {
 13     public:
 14         int ed, nx, w;
 15         
 16         Edge(int ed = 0, int nx = 0, int w = 0):ed(ed), nx(nx), w(w) {         }
 17 }Edge;
 18 
 19 typedef class MapManager {
 20     public:
 21         int ce;
 22         int* h; 
 23         Edge* es;
 24         
 25         MapManager() {            }
 26         MapManager(int n, int m):ce(-1) {
 27             h = new int[(n + 1)];
 28             es = new Edge[(m + 1)];
 29             memset(h, -1, sizeof(int) * (n + 1));
 30         }
 31         
 32         void addEdge(int u, int v, int w) {
 33             es[++ce] = Edge(v, h[u], w);
 34             h[u] = ce;
 35         }
 36         
 37         Edge& operator [] (int p) {
 38             return es[p];
 39         }
 40 }MapManager;
 41 
 42 typedef class Node {
 43     public:
 44         int p;
 45         int dis;
 46         
 47         Node(int p = 0, int dis = 0):p(p), dis(dis) {        }
 48         
 49         boolean operator < (Node b) const {
 50             return dis > b.dis;
 51         }
 52 }Node;
 53 
 54 int n, m;
 55 MapManager g;
 56 MapManager rg;
 57 int *prt;
 58 int *f1, *f2;
 59 boolean *flags;
 60 
 61 inline void init() {
 62     scanf("%d%d", &n, &m);
 63     g = MapManager(n, m << 1);
 64     rg = MapManager(n, m << 1);
 65     for (int i = 1, u, v, w; i <= m; i++) {
 66         scanf("%d%d%d", &u, &v, &w);
 67         g.addEdge(u, v, w);
 68         g.addEdge(v, u, w);
 69     }
 70 }
 71 
 72 priority_queue<Node> que;
 73 
 74 void dijstra(int s, int* &f) {
 75     f = new int[(n + 1)];
 76     memset(f, 0x3f, sizeof(int) * (n + 1));
 77     que.push(Node(s, f[s] = 0));
 78     while (!que.empty()) {
 79         Node e = que.top();
 80         que.pop();
 81         if (e.dis != f[e.p])    continue;
 82         for (int i = g.h[e.p]; ~i; i = g[i].nx) {
 83             Node eu (g[i].ed, f[e.p] + g[i].w);
 84             if (eu.dis < f[eu.p]) {
 85                 f[eu.p] = eu.dis;
 86                 que.push(eu);
 87             }
 88         }
 89     }
 90 }
 91 
 92 void dfs(int p) {
 93     for (int i = rg.h[p]; ~i; i = rg[i].nx) {
 94         int e = rg[i].ed;
 95         if (f1[e] + f2[e] == f1[n])
 96             prt[e] = e;
 97         else
 98             prt[e] = prt[p];
 99         dfs(e);
100     }
101 }
102 
103 int ans = (1 << 30);
104 inline void solve() {
105     dijstra(1, f1), dijstra(n, f2);
106     prt = new int[(n + 1)];
107     flags = new boolean[(m * 2 + 1)];
108     memset(prt, 0, sizeof(int) * (n + 1));
109     for (int i = 1, e; i <= n; i++) {
110         for (int j = g.h[i]; ~j; j = g[j].nx) {
111             e = g[j].ed;
112             if (f2[e] + g[j].w == f2[i]) {
113                 rg.addEdge(e, i, 0);
114                 flags[j] = true;
115                 break;
116             }
117         }
118     }
119     prt[n] = n;
120     dfs(n);
121     for (int i = 1, e; i <= n; i++) {
122         for (int j = g.h[i]; ~j; j = g[j].nx) {
123             e = g[j].ed;
124             if (!flags[j]) {
125                 if (f1[i] + g[j].w + f2[e] == f1[n] || f2[i] + g[j].w + f1[e] == f1[n])    continue;
126                 if (prt[i] != prt[e] && f1[prt[i]] <= f1[prt[e]])
127                     ans = min(ans, f1[i] + g[j].w + f2[e]);
128             }
129         }
130     }
131     if (ans == (1 << 30))
132         puts("-1");
133     else
134         printf("%d", ans);
135 }
136 
137 int main() {
138     init();
139     solve();
140     return 0;
141 }

写在后面的鬼扯

   由于这篇博客写了3个小时+,所以不能保证证明过程全是正确的,有问题请及时指出。

 

参考文献

  《excape解题报告》 by Unknown

  很抱歉,我真的不知道它的作者是谁。只是当作考试的题解发下来的资料。

 

特别鸣谢

  感谢YYR提供的资料以及许多骗分做法

  感谢Doggu和我一起研究这个问题

  感谢ZJC帮助我调试程序

 

(转载请注明出处:http://www.cnblogs.com/yyf0309/p/8563071.html)

bzoj 4283 魔法少女伊莉雅 - 最短路

标签:size   指定   nod   boolean   起点   pad   namespace   space   bsp   

原文地址:https://www.cnblogs.com/yyf0309/p/8563071.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!