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

题目传送门

  需要高级权限的快速通道

题目大意

  给定一个$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)

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

时间: 2024-11-08 19:36:58

bzoj 4283 魔法少女伊莉雅 - 最短路的相关文章

【Fate/kaleid liner 魔法少女☆伊莉雅】系列中实践的、新世代的动画摄影工作流

通常的日本动画的摄影中,是以追加Cell(celluloid 赛璐珞)与背景的合成滤镜处理为主,而在[Fate/kaleid liner 魔法少女☆伊莉雅]系列的,加入了自己使用3DCG软件来制作特效素材的新的摄影风格. 作为最后工程的摄影,也可以受益于3DCG软件 已经放映结束的本人气系列的第3季,[魔法少女☆伊莉雅 2wei Herz! ]中, Asahi Production 的中西康祐摄影导演带领的小组,在[Cell与CG的崭新融合]的概念下,实践了最新摄影工作流. [魔法少女☆伊莉雅

【bzoj4283】魔法少女伊莉雅

似乎是用最短路树随意判一下就好了. #include<bits/stdc++.h> #define maxn 100005 #define maxm 500005 #define INF 0x7f7f7f7f using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='

BZOJ 1975 魔法猪学院(K短路)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1975 题意:给出一个带权有向图.求一个最大的K使得前K短路的长度之和不大于给定的值Sum. 思路:首先,求出每个点到n的最短路.接着,使用优先队列,节点为(D,u).首先将(dis[1],1)进队.由于D在任意时候为一条1到n的路径的长度,那么对于边<u,v,w>,D-dis[u]+w+dis[v]为一条新的路径的长度. vector<pair<int,double>

bzoj 4399 魔法少女LJJ

4399: 魔法少女LJJ Time Limit: 20 Sec  Memory Limit: 162 MBhttp://www.lydsy.com/JudgeOnline/problem.php?id=4399 Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味:小猴在枝头悠来荡去,好不自在:各式各样的鲜花争相开放,各种树枝的枝头挂满

AC日记——魔法少女LJJ bzoj 4399

魔法少女LJJ 思路: 动态开点权值线段树+启发式合并: 来,上代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 400005 #define maxm 7000000 int ch[maxm][2],X,dis[maxm],tot,

【BZOJ4399】魔法少女LJJ 线段树合并

[BZOJ4399]魔法少女LJJ Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味:小猴在枝头悠来荡去,好不自在:各式各样的鲜花争相开放,各种树枝的枝头挂满沉甸甸的野果:鸟儿的歌声婉转动听,小河里飘着落下的花瓣真是人间仙境”SHY觉得LJJ还是太naive,一天,SHY带着自己心爱的图找到LJJ,对LJJ说:“既然你已经见识过动态树

NBUT 1010 魔法少女(DP)

[1010] 魔法少女 时间限制: 1000 ms 内存限制: 65535 K 问题描述 前些时间虚渊玄的巨献小圆着实火了一把. 在黑长直(小炎)往上爬楼去对抗魔女之夜时,她遇到了一个问题想请你帮忙. 因为魔女之夜是悬浮在半空的,所以她必须要爬楼,而那座废墟一共有n层,而且每层高度不同,这造成小炎爬每层的时间也不同.不过当然,小炎会时间魔法,可以瞬间飞过一层或者两层[即不耗时].但每次瞬移的时候她都必须要至少往上再爬一层(在这个当儿补充魔力)才能再次使用瞬移.爬每单位高度需要消耗小炎1秒时间.

BZOJ 1003 物流运输trans(最短路)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1003 思路:m个点e条边n天.给出每条边的权值以及有些点有些天不能走.对于某连续的两天i和i+1,若两天从起点到终点选择的路径不同需要额外代价K.求最小的总代价:ans=sum(每天的代价)+K*改变的次数.每天的代价定义为这一天s到t选择的路径的长度. 思路:令cost[i][j]表示从第i天 到第j天选择一条路径的最短路,f[i]表示前i天的总代价,则f[i]=min(f[j]+c

BZOJ 2753 滑雪与时间胶囊(最短路-克鲁斯卡尔)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2753 题意:一个n个点m条边的带权无向图,每个点有一个高度值h.某个从1号点开始遍历,每次走的边u到v,必须满足h[u]>=h[v].已知从当前点回到曾经遍历过的任意一个点是不需要走路的.求最多可以遍历多少个点?遍历这些点走的最小路程是多少? 思路:只记录h[u]>=h[v]的 边,因为其他边是无用的,这样其实是个有向图.首先从1BFS一次可以得到多少个点可以到达.然后将边排序,对于