hdoj 5257 翻转游戏
其实我在一年多前就在老刘的专题训练做过这个题了,队友问起这个题又复习了一下,还是有很多收获。唉唉,转眼都要退役了,时间过得真快
题意
度度熊最近迷上一个小游戏:Flip it。游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色。每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子),黑变白,白变黑。
度度熊希望把所有格子都变成白色的。不幸的是,有一些格子坏掉了,无法被按下。这时,它可以完成游戏吗?
题解
首先可以发现,如果确定了第一行或者第一列的每一个开关是否按下,那么其他所有开关是否被按就是确定的。
不妨设第一行的每个开关的状态为 \(x_i\),显然按两次以上开关没有意义,所以 \(x_i \in \{0, 1\}\)。设 \(f(i, j)\) 表示开关 \((i,j)\) 的状态, \(f\) 是一个关于 \(x_1,x_2,x_3\dots x_m,x_{m+1}\) 的 \(m+1\) 元一次函数,且系数为 \(0\) 或者 \(1\)。这里多了一个变量 \(x_{m+1}\),之后会解释。
对于第一行 \(f(1,j)=x_i\)。考虑一行一行的转移 \(f\),因为 \((i, j)\) 开关恰好会影响 \((i-1,j)\) 的格子颜色,而影响那个格子颜色的其他四个开关的状态 \(f(i-1,j)\), \(f(i-1,j-1)\), \(f(i-1,j+1)\), \(f(i-2,j)\) 已经算出,再结合 \((i-1,j)\) 本来的颜色就可以递推出 \(f(i,j)\),这也解释了为什么要多设一个 \(x_{m+1}\),实际上 \(x_{m+1}\) 是一个恒 \(1\) 的变量,作用是考虑格子本来的颜色带来的影响。
可能有人会疑惑,递推 \(f\) 的时候为什么不考虑相邻两列互相影响。这是因为 \(f\) 表示的是开关是否按下,而不是格子的颜色状态。
实际上这样做之后,保证了当前这一行无论是什么颜色,下一行的开关始终能让它们变成白色。但是最后一行就需要自身保证操作完之后是白色的,这也是约束条件。