POJ 1222 熄灯问题

    题目给出一个5*6的矩阵:0表示灯是灭着的,1表示灯是开着的,要求给出每盏灯的开关情况,让所有灯灭掉。开关规则:当按下一盏灯的开关,它上下左右四盏灯也会开关(亮的灭掉,暗的亮起),边角和边缘影响的灯会有不同。

    该如何确定是否按下每盏灯的开关呢?最简单就是用穷举。每盏灯有两种情况,5*6共30盏灯,一共2^30种可能。太多了,应该尽可能地“减枝”,让穷举范围尽可能小,以不至于超时。

    观察发现,当我们确定了第一行的开关情况,第一行依然亮着的灯,只能通过第二行开关来灭掉,同理,第二行仍然亮着的灯只能通过第三行来灭掉,并且第一行的情况不会影响到第三行。由此递推得知,第i+1行的开关,由第i行开关来确定,第i行开关又由第i-1行开关确定···所以,只要枚举第一行,每一行的开关就都会被确定,然后,看最后一行开关确定后,该行是否还有灯亮,就能知道这种开关情况是否是解。

    该题有三个重点,一是用什么来表示第 i+1 行第 j 列的开关与第 i 行第 j 列的开关之间的关系,二是如何处理边缘和边角的开关,三是如何枚举第一行。

    一、第 i+1 行第 j 列的灯是否开关由第 i 行第 j 列的灯是否摁下开关及输入中第 i 行第 j 列灯是亮的还是暗的来确定:有四种情况:

    1.(i,j)灯摁下开关,题目中它是亮的,那最后是暗的,(i+1,j)灯不用摁。

    2.(i,j)灯不摁开关,题目中它是亮的,那最后是亮的,(i+1,j)灯要摁。

    3.(i,j)灯不摁开关,题目中它是暗的,那最后是暗的,(i+1,j)灯不用摁。

    4.(i,j)灯摁下开关,题目中它是暗的,那最后是亮的,(i+1,j)灯要摁。

    这里就要用到求余(对2求余)的操作,余数为0不摁,余数为1要摁。

    但是,第 i 行第 j 列的灯最终是否摁下开关是要看它上、左、右三盏灯以及它本身的情况的,如果它们的情况加合,对2求余为0,说明效果互相抵消,相当于没有摁下开关;余数为1,说明最终效果是摁下。

    可能你会问,这样子,第 i-1 行开关情况不是影响到了第 i+1 行了吗?我们可以这样说,与第 i+1 行开关有直接关联的是第 i 行开关,而第 i 行第 j 列最终的开关情况,受到第 i-1 行第 j 列的开关影响。

    最终公式:press[i+1][j]=(press[i][j]+puzzle[i][j]+press[i-1][j]+press[i][j+1]+press[i][j-1])%2

    二、我们可以把矩阵扩大,变成6*8的,把他们的开关情况置为0,让边角和边缘的灯和正常灯一样运算且结果不变

    三、可以用二进制的方法来枚举第一行,要自己模仿一遍进位,有几个易错的地方要注意,也写在了程序里头

    我的代码:https://paste.ubuntu.com/p/2ts44KkkMK/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值