两个问题的对比

0 问题描述

问题1(CF390C): 给定若干行聊天记录 “发言人: 话”, 有些聊天记录的”发言人”是缺失的, 已知相邻对话发言人一定不同, 且每个发言人说的话里都不会包含自己的名字, 现给定可能的发言人的集合, 请填充每个对话的发言人.(来自Codeforces Round 390: http://codeforces.com/contest/754/problem/C)

问题2(LC36): 给定一个9*9的矩阵, 有些元素为空, 要求使用1-9填充空元素, 使每行, 每列, 每个3*3小矩阵(共9个)中都包含1-9这9个数字.(来自 leetcode: https://leetcode.com/problems/sudoku-solver/?tab=Description)

先说结论, 两个问题非常相似, 但是第一个问题可用动态规划求解; 由于状态转移方程极难表述, 第二个问题不能用动态规划求解

1 用一张表表述问题

对于LC36, 在初始条件下, 如果我们不对矩阵进行任何填充, 那么问题的当前状态可以用一张表进行描述, 注意, 我们可以按照从上到下,从左到右的方式遍历矩阵的每个元素, 这样我们用一维序列描述二维矩阵:

元素编号可能的填充数字
1 a11,a12,...
2 a21,...
81 a81,1,a81,2,...

同样地, 对于CF390C, 在我们填写发言人之前, 问题的初始状态也可以用一张表描述:

聊天记录可能的发言人
第1条记录 b11,b12,...
第2条记录 b21,...
第n条记录 bn1,...

一旦我们开始填写矩阵/发言人, 那么上述两张表的状态就会改变, 而且改变总是会让每行的”候选集”缩小.即, 我们列出的每行的候选集一定是最终结果的超集.

2 使用动态规划描述问题

在LC36的题意下, (i,j) 表示填第 i 个元素, 使用数字j, 然后问题跳转到 (i+1,j)
在390C的题意下, (i,j) 表示填第 i 个对话, 使用第j个人, 然后问题跳转到 (i+1,j)

乍看上去, 这两个问题是一样的. 可是我们遗漏了一很关键的东西, 就是我们对 (i+1,j) 的表述是不完整的.因为我们无论何时, 只要我们填写了 i , 那么在我们填写i+1时就会受到我们刚才的填写行为的约束. 即问题 i 的决策会对问题i+1产生影响, 但是我们并没有表述出这种影响.

3 重新描述问题

对于LC36:

  1. (i,j) 表示第 i 个格子, 使用j
  2. 问题跳转到 (i+1) , 引入额外的约束:”不能使用 j ”, 为了表述额外约束, 我们需要修改问题的表示形式
  3. 于是我们返回去重新表述(i): 填写第 i 个格子, 使用数字j, 不能使用的数字列表为 k , 记为(i,j,k)
  4. 问题再次跳转到 (i+1) : 填写第 i+1 个格子, 使用数字 j , 不能使用的数字列表为 k,j , 记为 (i+1,j,[k,j])

这样可以构造DP问题 [y,x,i,M] 表示在不能使用数字的屏蔽码为M的情况下用 i 台填写格子(y,x),并且不会破坏矩阵性质的可能性(可能/不可能), 复杂度是: 9*9*9*512 < 1000 * 600 = 600, 000, 貌似可解

而对于390C:

  1. (i,j) 表示, 填写第 i 行, 使用人物j
  2. 然后跳转到 (i+1) , 问题表述为填写第 i+1 行, 使用人物 j , 不能使用人物 j , 引入新的约束, 需重新表示问题
  3. 重新表述i为, 填写第 i 行, 使用人物j, 不能使用人物 k , 记为(i,j,k)
  4. 再次跳转到 i+1 , 问题表述为填写 i 个格子, 使用人物j, 不能使用人物 j , 记为(i+1,j,j)

至此, 可以构造DP问题 [i,j,k] , 表示从第 i 个人开始填写, 使用j号人物, 不能使用 k 号人物, 最终可以成功填写的可能性(可能/不可能).

4 分析

这两个问题再以下方面是相同的:

  1. 都是一个一个的填写, 并且每个都有个候选列表
  2. 填写一个以后, 会影响其他人的填写

但是CF390C和LC36相比有个关键的不同点: 前者跳转时, 会不携带来自(i1)的约束, 而后者会携带来自 (i1) 的约束:

  1. 对于CF390C, 问题的跳转方式是 (i,j,k)(i+1,j,j) , (i+1) 的第三个状态与 i 的第三个状态无关.
  2. 对于LC36, 问题的跳转方式是(i,j,[k])(i+1,j,[k,j]), (i+1) 的第三个状态与 i 的第三个状态有关.

至此, 我们发现第一个是普通的动态规划, 第二个似乎是状态压缩动态规划.可是真是这样吗?

对于CF390C, 我们在计算(i,j,k)时可以很方便地算出 (i+1) 的两个状态参数:

  • j : 遍历每个可能的发言人
  • j : 直接使用问题i的第二个状态填充

然而, 对于LC36, 我们在计算 (i,j,k) 时却很难算出 (i+1) 的第三个参数!我们来看第三个参数的意义:不能使用的数字集合.这个参数的计算过程是这样的: 一方面, 如果 i 号元素是定值, 那么第三个参数k也是定值, 直接计算;另一方面, 如果 i 号元素为空, 那么第三个状态k的计算要考虑如下因素:

  1. 元素在矩阵中受到的天然限制: 行, 列, 小3*3小矩阵中的元素.这个限制就是第1节中的表的限制.
  2. 元素受到 i 的限制: 父元素i有自己的不可用数字集合, 这个集合中的数字来自于父元素 i 的表, 以及父元素i的父元素 (i1) .

这样一来, 如果你要计算 (i+1) 的第三个参数, 必须清楚地知道, 父元素不可用数字集中每个数字是如何生成的:

  1. 对于受到原始限制的数字, 我们可以通过 i i+1的想对位置, 进行修正. 比如, 若 i (i+1)在同一行,且在同一个小矩阵中 那么我们从 i 的原始限制集中去掉通过列限制提供的数字.
  2. 对于受到i的先前元素限制的数字, 我们必须找到他们的生成位置, 然后根据生成位置和 (i+1) 的想对位置, 来计算 (i+1) 的不可用数字集合.

稍加思考就会知道, 上述两个步骤, 每一步都是几乎不可实现的.因此, LC36虽然和CF390C非常像, 但是后者可以用DP求解, 但是前者很难用DP求解.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值