背景
(freshwater) , (Luogu) (P2622)
题意
给定 (n) 盏灯,一开始全都是开着的。有 (m) 种操作,每种操作形如一个长为 (n) 序列 (a) , (a_i) 表示第 (i) 盏灯进行的操作: (a_i=1) 表示把第 (i) 盏灯关掉, (a_i=-1) 表示把第 (i) 盏灯打开,否则什么也不做。求使得所有灯都关上的最小操作次数。
解法
从朴素解法开始:由于 (n leqslant 10) ,所以所有的灯可以从左往右压成一个 (n) 位的二进制数(显然该数不超过 (1024) )。
每个操作 (i) 其实可以压成两个二进制数 (t_{i,1}=2^n-1,t_{i,2}=0) ,具体做法是考虑进行的操作的本质:遇到 (a_j=1) 的就把 (t_{i,1}) 二进制表示下的第 (j) 位变成 (0) ( (x wedge 0=0) ),遇到 (a_j=-1) 的就把 (t_{i,2}) 二进制表示下的第 (j) 位变成 (1) ( (x vee 1=1) )。则对于一个灯的状态 (x) 进行操作 (i) 之后的状态就是 ((x wedge^{[1]} t_{i,1}) vee^{[2]} t_{i,2}) 。然后 (dfs) 即可。然后你就会获得 (50pts) 的好成绩。
考虑优化:显然每个灯的状态都不会经过超过 (1) 次,于是可以给经过的状态打个标记。然后你就会获得 (70pts) 的好成绩。下载数据,容易发现无法判断无解。
(trick)
考虑换一种搜索方法。
可以考虑用步数作为搜索的阶段,也即搜索树的深度。不妨换用 (bfs) ,每次只把没走过的合法的状态推进队列。若队列为空时仍未更新答案则判定无解即可。
细节
写之前一定要想清楚转移的设计,要敲定所有细节,否则调试会很麻烦。