LOJ#3291.「CEOI2014」城墙
作者:互联网
Problem
\(n\times m\) 的网格,有些格子上有村庄,保证第一行第一列是个村庄。
你需要在格子的边缘上建篱笆,每个格子的每条边都有一个代价,你需要让篱笆形成一个圈把所有村庄围住。
注意一条边两侧可以建两个篱笆,但需要付出两倍的代价,如下图。
你要让花费的总代价最小(例如上图)
\(n,m\leq 400\)。
Solution
暴力
发现一个点被篱笆框起来当且仅当它走到图外面经过奇数条边界。
设 \(f(S,x,y)\) 表示篱笆从 \((0,0)\) 到 \((x,y)\),并且对于任意 \(v\in S\),篱笆经过了 \(v\) 的右侧奇数次 的最小代价(\(S\) 是村庄的一个集合,\((x,y)\) 为任意一个格点)。如果 \(V\) 是所有村庄的集合,那么答案就是 \(f(V,0,0)\)。
这样可以获得 \(30\) 分。
正解
考虑如下的结论:把 所有村庄的左上角到整个网格的左上角的最短路 全部标记出来,则必然存在一种最优方案使得篱笆包含了全部的这些最短路。
假设最终答案的区域没有包含所有的最短路,即如下图:(绿色的路径就是 \(v\) 的左上角到整个网格左上角的最短路)
显然把黄色区域添加进去不会使答案变劣。因此不断这么操作就可以把所有最短路都添加进去。
利用这个结论和暴力中的 DP 可以获得 \(60\) 分的好成绩。
可以考虑 把每个格点分成四个点(具体来说,是把方格角上的点拆成左上、右上、左下、右下四个点,并在这四个点中的相邻节点之间连一条长度为 \(0\) 边),如下图所示。然后由于要保证不穿过这些最短路和村庄的四条边,
- 对于村庄,将村庄所在的网格四个点删掉
- 对于最短路,把最短路经过的边断掉
删起来比较麻烦。其实可以在初始连边的时候,当且仅当它们之间没有穿过任何一条最短路,且它们都位于所有村庄之外,相邻两个节点之间才连边。
跑一遍从 \((0,0)\) 右上到 \((0,0)\) 左下最短路即可。这样可以保证篱笆是封闭的。
图中,绿色表示村庄和村庄左上角到整个网格的左上角的最短路,橙色的两个点表示起点和目标,短边(即一个点拆分成的四个点中,相邻两个点之间的边)的代价为 \(0\),长边的代价就是对应边的代价。橙色的路径是其中一种最优方案。
总复杂度 \(\mathcal O(nm \log nm)\)。
标签:LOJ,短路,CEOI2014,网格,村庄,篱笆,左上角,代价,3291 来源: https://www.cnblogs.com/mytqwqq/p/15193658.html