【发布时间】:2018-03-27 08:36:51
【问题描述】:
UPD。我解决了这个问题。
让DP[i][vertex_a][vertex_b] 是访问过i 城市的状态,两个玩家站在顶点vertex_a, vertex_b (保证其中一个站在list[i])。 WLOG 假设vertex_a ≤ vertex_b 因为这个DP 表不包含有关球员位置的信息。从DP[i][vertex_a][vertex_b]只能到达三种状态,即DP[i + 1][vertex_a][vertex_b]、DP[i + 1][list[i]][vertex_b]、DP[i + 1][vertex_a][list[i]]。我们也只需要存储两层DP,因此只需要sizeof(int) * 2 * 200 * 200字节来计算最优路径成本。要获得路径,last_move_id[i][vertex_a][vertex_b] 将携带有关在状态DP[i][vertex_a][vertex_b] 移动的玩家的信息,last_move_positions[i][vertex_a][vertex_b] 存储玩家到达list[i] 的顶点数。由于顶点数不超过 200,因此将它们保存为 byte,因此每个数组的 sizeof(byte) * 1000 * 200 * 200 字节。为了维护这些数组,必须有另一个数组positions[i][vertex_a][vertex_b][3] 携带有关每个玩家位置的信息,只需要最后两层,因此sizeof(byte) * 2 * 200 * 200 * 3 字节为这一层。时间复杂度O(N * L * L)。
我的C++ 实现使用76Mb 和320 ms。
我正在努力解决来自俄罗斯在线评委http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=3379 的以下竞争性编程问题。按照规定,我记得一定要提供问题的根源
很遗憾,没有英文版的网站,所以我将尝试描述问题。
输入由完整的有向图
G和L顶点和一些顶点列表(长度最多N)组成。三个人分别从顶点1, 2, 3开始。他们必须访问输入列表中的每个顶点,顺序很重要,顶点i + 1必须在i之后访问。在某个时间点,只有一个人可以移动(如果一个人从某个先前的顶点移动到顶点i其他人静止不动,他们不能平行移动)。如果人/玩家站在顶点i并且必须移动到顶点j他必须采取边缘(i, j)而不是到顶点 j 的最短路径(Floyd-Warshall 算法不能用来加速这里的计算) .一个人可以访问一个顶点就足够了,这意味着人 1 可以访问所有顶点,而其他人则静止不动。边(i, i)的成本始终为0,没有多重边,所有边的权重都是非负的,G表示为L x L邻接矩阵。从列表中输出这三个人访问顶点的最短路径成本,并输出访问每个顶点的人。输入要访问的顶点列表是一个多重集(N可能大于L)
我发现这个问题有点类似于 城市序列的两人遍历 问题,除了这是一个 三人 版本并且它们以不同的开头位置和一个主要区别是人们必须访问允许重复的特定顶点序列。我已经研究过这个问题的解决方案,时间复杂度是O(L^3)
对于城市序列的两人遍历,我的问题是O(N^4),这太慢了,因为即使O(N^3)算法也不会满足时间限制,我想像@ 987654365@ 可以工作。
约束:
3≤L≤200,1≤N≤1000
0≤边权≤2000
时间限制:1s,内存限制为256 Mb
我也确信这个问题可以使用 64 Mb 来解决。
这个问题被标记为2D dynamic programming。
我无法真正想出这个确切的2D 动态。我想到了一个非常简单的方法来解决这个问题:
三个人的初始状态是(1, 2, 3)。在处理我们计算的第一个顶点时:
1:(list[1], 2, 3) = (1, 2, 3) + weight(1, list[1])
1:(1, list[1], 3) = (1, 2, 3) + weight(2, list[1])
1:(1, 2, list[1]) = (1, 2, 3) + weight(3, list[1]).
正如人们所看到的,这是一个4D 动态表,但我认为保持当前迭代的数量是不必要的,使其成为3D 之一。此外,人们可以注意到,对于计算 (i+1)-th 层,第一层只需要关于 i-th 层的信息,这使得它成为一个很好的内存优化。尽管如此,如果我们忘记图中最多只有 200 个顶点,并将状态视为元组(i, j, k),其中 i,j,k 是最后阶段玩家 1、2 的数量, 3 移动 at,这意味着在 m-th 阶段 i, j, k 之一等于 m。按照这个逻辑并考虑所有可能的重复,在 m-th 阶段的不同元组的数量是:
Number_at_stage(m) = Number_at_stage(m - 1) + 6 * (m - 1),Number_at_stage(1) = 3, Number_at_stage(2) = 9, Number_at_stage(1000) = 2991009.
Number_at_stage(1)我从以下想法得到:
(0, 0, 0) -> (1, 0, 0), (0, 1, 0), (0, 0, 1)
我已经将阶段1..1000 的不同元组的数量相加,得到了一个可怕的997004997 数量,几乎是十亿。这意味着代表此类移动的不同元组的数量是渐近三次的(并不奇怪,但很明显)。我不明白如何改进这个想法。以这种方式思考,我不知道如何处理诸如 (i, j, k) 和 (k, j, i) 之类的状态,因为它们实际上是等价的,因为可以基于相同的步骤集在这些上。我只是不知道如何处理这些状态并保存信息什么人访问了哪个城市(简单的多维数组?)。
我的下一个想法是有一个二维 DP(i, j) 存储从 i 到 j 元素的子列表的最佳距离总和。如果索引从 1 开始,答案将存储在 DP(1, N) 中。我可以计算长度为 1、2、... N 的所有子集。这个想法有一个主要问题,我不知道如何在不知道玩家可以站在的所有潜在位置的情况下处理 DP(i, j)(列表中的所有元素都在 i 之前以及初始位置 1、2、3)。我也不知道如何确定是哪个玩家用这种方法做出了动作。
您能帮我找到 2D 动态吗?
【问题讨论】:
标签: algorithm dynamic-programming