Note: 本文最初于 2011年01月24日 星期一 20:08 在 hi.baidu.com/lydrainbowcat 发表。
题目:http://www.tyvj.cn/p/1266
解法1:直接进行全局搜索+Hash
看到这个题,大家首先想到的肯定是枚举——每个开关点或者不点,时间复杂度是O(2^25),3000多万,单纯的一组可以过,但是题目里有多组数据(出题人当然要防止你爆搜啦),所以不能这么裸的搜。
由于只有6步,我们完全可以倒着搜索出有哪些情况可以在6步以内实现全部亮,然后把这些方案Hash一下,以后就可以直接O(1)的使用啦。
★ 解法2:枚举第一行的状态+判定
这是一种较为简洁高效的做法。
我们经过认真的分析可以发现,当第一行的状态确定不再点以后,剩下的行的状态也就确定了——上一行那一列是0,就点0下边那个(因为上边的行已经不能点了),到最后一行后判断看最后一行是不是都亮了,亮了就更新ans。
所以我们只需要枚举第一行的2^5=32种情况,执行上述扫描判定即可。枚举这32种情况,可以使用DFS,也可以使用位运算——枚举0~31,某一位是1/0表示第一行对应列点/不点。
解法3:高斯消元求解xor方程组
一个格子最后亮或不亮,与它上下左右相邻的格子以及它自己是否点击有关。若它所在十字中有奇数次点击,则最终状态与初态相反,否则与初态相同。
由此我们可以将其等效为xor方程,每个格子对应一个变量,取值为0表示不点,取值为1表示点。每个格子以及影响它的格子对应的变量xor起来,应该等于0(与初态相同)或1(与初态不同),即一个xor方程。最后用高斯消元求出该方程的解即可。
解法2参考程序:
type arr=array[0..6,0..6]of integer; var a:arr; i,j,k,ans,n:longint; ch:char; function judge:boolean; var i:longint; begin judge:=true; for i:=1 to 5 do if a[5,i]=0 then judge:=false; end; procedure dfs2(i,step:longint); var j:integer; begin if i=6 then begin if (judge)and(step<ans) then ans:=step; exit; end; for j:=1 to 5 do if a[i-1,j]=0 then begin inc(step); a[i-1,j]:=1; a[i,j]:=1-a[i,j]; a[i+1,j]:=1-a[i+1,j]; a[i,j-1]:=1-a[i,j-1]; a[i,j+1]:=1-a[i,j+1]; end; dfs2(i+1,step); end; procedure dfs1(i,now:longint); var re:arr; begin re:=a; dfs2(2,now); a:=re; if i=6 then exit; dfs1(i+1,now); a[1,i-1]:=1-a[1,i-1]; a[1,i]:=1-a[1,i]; a[1,i+1]:=1-a[1,i+1]; a[2,i]:=1-a[2,i]; dfs1(i+1,now+1); a[1,i-1]:=1-a[1,i-1]; a[1,i]:=1-a[1,i]; a[1,i+1]:=1-a[1,i+1]; a[2,i]:=1-a[2,i]; end; begin readln(n); for i:=1 to n do begin for j:=1 to 5 do begin for k:=1 to 5 do begin read(ch); a[j,k]:=ord(ch)-ord('0'); end; readln; end; if i<n then readln; ans:=maxint; dfs1(1,0); if ans<=6 then writeln(ans) else writeln(-1); end; end.