Module: 动态规划中的模式 - 2


Problem

4 /5


矮人

Theory Click to read/hide

免责声明:下面描述的方法并不通用,但它通常可以解决问题或帮助您找到正确的解决方案。

如果您需要检查问题中是否存在排列,或者找到匹配的排列数,或类似的东西,那么您应该考虑使用动态子集编程。

主要参数将是一个位掩码,它将显示哪些元素已经包含在排列中,哪些没有。通常还需要第二个参数,指示最后包含哪个元素。

通常可以在图形路径的上下文中看到排列。因此,让我们考虑一个经典的例子——哈密顿路径问题。
哈密​​顿路径是通过图的每个顶点恰好一次的简单路径。它可以简单地表示为长度为 n 的排列,其中 n 是顶点数。此排列中的顺序将指示遍历此路径中的顶点的顺序。

为了检查图中是否存在哈密顿路径,让我们开始动态 dp[mask][last] - 是否有一条简单的路径绕过掩码位掩码中标记为 1 的顶点并在最后一个顶点结束。
初始值将是 dp[2i][i] = true,其余为 false,这意味着总是有一条空路径从任何顶点开始。
dp[mask][last] 中的值为 true 我们将在“扩展路径”的意义上向前转换。也就是说,我们将寻找在掩码中标记为零的顶点数(我们还没有在途中访问它们),同时从 last 到这个顶点有一条边(路径必须由现有边扩展)。也就是说,我们做 dp[mask | 2k][k] = true 如果 dp[mask][last] = true AND mask & 2k = 0(顶点k还没有被访问过)并且最后有一条边->; k.
最终,如果全一位掩码和任何最后一个顶点的参数在 dp 中存在真值,则存在哈密顿路径。

Problem

有一次,矮人夸克偶然发现了一张藏宝图。地图上标记了 N 个可以找到宝藏的点。所有点都从 1 到 N 编号。对于每对点,夸克知道连接它们的道路长度。夸克从第 1 点开始寻找。在开始漫长的旅程之前,狡猾的矮人划掉了他认为不可能有宝藏的点。保证第 1 点永远不会被划掉。之后,夸克选择了一条通过地图上所有剩余点的路线。该路线不会多次通过同一点。夸克只能在连接未交叉点的道路上行走。

夸克想选择一条最小长度的路线。为夸克找这样一条路线是很有必要的。

输入
第一行包含一个整数 N (1 ≤ N ≤ 15) ——地图上标记的点数。接下来的 N 行包含点之间的距离。第 (i+1) 行包含 N 个整数 di1,di2, diN —从第 i 个点到所有其他点的道路长度。保证dij=dji, dii=0 and 0 <dij <; 100。第 (N+2) 行包含一个整数 Q (1 < Q ≤ 1000) ——用于删除此地图的点的选项数。以下 Q 行包含对删除选项的描述。描述以数字 C 开头(0 ≤ C < N)——根据夸克的说法,宝藏不可能存在的点数。接下来的 C 数字给出了这些点的编号。

印记
打印 Q 行。在每一行中打印一个整数——具有相应删除点选项的最小路径的长度。
例子
<头> <正文>
# 输入 输出
1 3
0  45 10
45 0  30
10 30 0
2
0
1 3
40
45
2 5
0  14 20 17 14
14 0  15 19 18
20 15 0  15 16
17 19 15 0  14
14 18 16 14 0
2
3 5 4 3
0
14
58