北大ACM2965 - The Pilots Brothers' refrigerator(枚举)

来源:互联网 发布:橙子网络 编辑:程序博客网 时间:2024/06/11 17:24

1.1.1           中文题目

一个门上有16个把手,并组成4x4的矩阵,把手有开有关,当把手所有都处于打开状态,则门就打开了。但是改变一个把手的状态,那么把手所在的行和列的所有把手的状态全部都改变。

当给定把手的初始状态后,求出最少需要改变多少个把手的状态就可以将门打开。

1.1.2           算法分析

根据网上提示,这个题目使用枚举,所以我也就直接使用的枚举。

简单思路

要想获得最少修改把手的个数,我们从1开始枚举,将所有把手改变一次,验证是否可以将门打开,如果能,则表明最少需要1次,如果不能,则验证2是否能够将门打开,以此类推,直到将门打开。

循环验证一个或者多个把手,很自然想到使用递归办法,(关于通用递归方法剖析,请查看我对递归的分析,http://blog.csdn.net/gykimo/article/details/8449131)。本题我的递归思路如下:

要想验证改变N个把手的状态是否可以将门打开,则首先应该将第一个把手改变状态,然后在余下的15个把手里面验证改变N-1个把手状态是否可以将门打开,如果能,则停止,如果不能,则将第2个把手改变状态,然后在余下的14个把手里面验证改变N-1个把手状态是否可以将门打开,以此类推。更一般的说明应该如下,假设现在已经在前p个把手里面改变了m(m<=p)个把手的状态,并且m把手是第p 个把手。验证在余下16-p个把手里面改变N-m个把手的状态是否可以将门打开,如果能,则停止,如果不能,则将第p+1个把手设为要改变的第m个把手,然后验证在余下16-p-1个把手里面改变N-m个把手的状态是否可以将门打开,依此类推。

数据结构

matrix[4][4] :把手矩阵,共16个

switchnum :需要改变状态把手的个数

递归函数

bool exe(int handle_index, inthandle_location)

handle_index :第几个需要改变状态的把手(1-switchnum)

handle_location :第handle_index个把手在所有把手中的位置(0-15)

改变第handleIndex及后面switchnum-handleIndex个把手后是否能够将门,如果打开返回true,如果不能打开,返回false

递归步骤

1.      设置阀值
第handle_index个把手位置是否有效,判断方法: handle_location + (switchnum - handle_index) > 15
如果位置无效,则返回false。

2.      处理
保存当前把手矩阵状态,因为如果当第handleIndex把手在handleLocation位置无法将门打开,则应该将把手矩阵状态恢复到未尝试开启时的状态。
改变handleIndex把手状态,也就是改变handleLocation位置的把手状态。

3.      递归
如果handleIndex把手后面还有把手,改变handleIndex把手后面的把手状态

4.      合并
如果门已经开启,则返回true
如果门没有开启,并且第handleIndex把手还没有到最后一个有效位置,则将handleIndex把手置为下一个位置。注意,应该将把手矩阵状态恢复到开始状态。
否则,否则返回false

代码

         http://download.csdn.net/detail/gykimo/4939694

         结果:469MS 688K

1.1.3           算法优化

上面的算法只是枚举所有情况,没有进行任何剪枝。我们可以分析下这个题目的特点,可以进行部分优化,我们通过分析可以得到以下的定理和推论。

定理一

         一个把手最多只能改变一次状态,多次无意义。

证明:

         如果把手h改变了2次,那么把手h经过2次改变后,状态未发生变化,根据数学归纳法,很容易证明h改变偶数次状态,h的状态不发生变化,所以h改变偶数次无意义;

         如果把手h改变了3次,那么状态和h改变1次状态是一样的,根据数学归纳法,很容易证明h改变多余1次的奇数次状态,h的状态和改变1次的状态一样。

         所以,定理成立。

推论1

         最多改变16个把手的状态就可以将门打开。

推论2

         以任意顺序改变选定的m个把手状态后,16个把手的状态和门的状态是一定的,即和操作的顺序无关。

证明:

         改变一个把手,就改变把手所在行和列的所有把手,也就是m个把手选定后,那么某个行和列改变状态的次数是一定的,所以不管m个把手改变顺序如何,最后状态是一定的。证毕。

 

当然以上的定理和推论对于优化没有任何意思,还有一些现象有助于优化算法,如当只有一行和一列的把手状态为关闭时,改变交点把手,就可以将门打开,其他情况都不能改变一次把手状态就可以将门打开,也可以分析改变2次或者多次把手时,需要什么样的情况,由于没有细致研究其中的规律,所以也就没有对代码进行优化。

 

另外一个问题,不管初始状态如何,肯定可以将门打开吗?