问题描述
  有一个由按钮组成的矩阵,其中每行有6 个按钮,共5 行。每个按钮的位置上有一盏灯。
当按下一个按钮后,该按钮以及周围位置(上边、下边、左边、右边)的灯都会改变一次。即,
如果灯原来是点亮的,就会被熄灭;如果灯原来是熄灭的,则会被点亮。在矩阵角上的按钮
改变3 盏灯的状态;在矩阵边上的按钮改变4 盏灯的状态;其他的按钮改变5 盏灯的状态。
在下图8-1 中,左边矩阵中用X 标记的按钮表示被按下,右边的矩阵表示灯状态的改变。
与一盏灯毗邻的多个按钮被按下时,一次操作会抵消另一次操作的结果。在图8-2 中,第2
行第3、5 列的按钮都被按下,因此第2 行、第4 列的灯的状态就不改变。根据上面的规则,
我们知道:
1) 第 2 次按下同一个按钮时,将抵消第1 次按下时所产生的结果。因此,每个按钮最多
只需要按下一次。
2) 各个按钮被按下的顺序对最终的结果没有影响。
3) 对第 1 行中每盏点亮的灯,按下第2 行对应的按钮,就可以熄灭第1 行的全部灯。如
此重复下去,可以熄灭第1、2、3、4 行的全部灯。同样,按下第1、2、3、4、5 列
的按钮,可以熄灭前5 列的灯。

对矩阵中的每盏灯设置一个初始状态。请你写一个程序,确定需要按下哪些按钮,恰好
使得所有的灯都熄灭。

输入数据
第一行是一个正整数 N,表示需要解决的案例数。每个案例由5 行组成,每一行包括6
个数字。这些数字以空格隔开,可以是0 或1。0 表示灯的初始状态是熄灭的,1 表示灯的
初始状态是点亮的。
输出要求
对每个案例,首先输出一行,输出字符串“PUZZLE #m”,其中m 是该案例的序号。接
着按照该案例的输入格式输出5 行,其中的1 表示需要把对应的按钮按下,0 则表示不需要
按对应的按钮。每个数字以一个空格隔开。
输入样例
2
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
0 0 1 0 1 0
1 0 1 0 1 1
0 0 1 0 1 1
1 0 1 1 0 0
0 1 0 1 0 0
输出样例
PUZZLE #1
1 0 1 0 0 1
1 1 0 1 0 1
0 0 1 0 1 1
1 0 0 1 0 0
0 1 0 0 0 0
PUZZLE #2
1 0 0 1 1 1
1 1 0 0 0 0
0 0 0 1 0 0
1 1 0 1 0 1
1 0 1 1 0 1

我的解题思路:

  首先根据题目的提示我们可以知道,每行(列)的亮灭只需它下一行(列)的相应的灯来控制。那么我们就可想想到,第一行靠第二行的控制来全灭,同理,第二、三、四行都可以全灭。但这是还有第五行怎么控制呢?没办法了。。。。就在这卡住了。肿么办?枚举!对了,就是枚举!既然最后一行我们不可以控制,那么我们就可以枚举第一行按灯的情况。按或不按,总共2^6次方种情况,不多,只要把第一行的按灯情况,确定了,那么后面的都好办了。然后就遍历第一行的每种按灯情况,看一下哪一种情况下,刚刚好第五行的灯也全灭,那么这个就是我们想要的情况了。

  但是在具体程序的实现上,还有很多的技巧要注意的。首先,它是个5X6的矩阵,但是我却用了6x7的矩阵,这样在按边上(5X6的边)的灯的时候,我们也同样适用是五个灯同时变了,这样用一个函数就能实现,不用考虑两种情况。最后输出只把5X6矩阵输出就好了。对于第一行的情况的遍历,我用的是递归的方式来遍历。因为前段时间刚刚好把递归(recursion)又学了一遍。使用递归来实现遍历,屡试不爽啊!主要注意的是状态的恢复,主要是递归退出时候的状态恢复。其它的就没有什么了。具体的看代码吧。

//遍历搜索空间的例子:熄灯问题

#include <stdio.h>
#include <stdlib.h>int puzzl[7][8],press[7][8];  //这有个技巧
int nCase;
FILE *fp;void input_data()
{int row,col;for (row = 1; row < 6; row++){for (col = 1; col < 7; col++){fscanf(fp,"%d",&puzzl[row][col]);}}
}void print_press()
{int row,col;for (row = 1; row < 6; row++){for (col = 1; col < 7; col++){printf("%d ",press[row][col]);}printf("\n");}
}void do_press(int row,int col)
{int j;for (j = -1; j < 2; j++){if (puzzl[row][col+j] == 1){puzzl[row][col+j] =0;}else{puzzl[row][col+j] = 1;}}for (j = -1; j < 2; j++){if (j == 0){continue;}if (puzzl[row+j][col] == 1){puzzl[row+j][col] = 0;}else{puzzl[row+j][col] = 1;}}press[row][col] ^= 1;}void deal_first_line(int col)  //col 从1开始
{int i,m,n,nFlag;if (col == 7){//此时,第一行的状态已经定了。for (m = 1; m < 5; m++){for (n = 1; n < 7; n++){if (puzzl[m][n] == 1){do_press(m+1,n);}}}nFlag = 1;for (i = 1; i < 7; i++){if (puzzl[5][i] == 1){nFlag = 0;break;}}if (nFlag){//最后一行全为零printf("PUZZLE #%d\n",nCase);print_press();return;}}else{for (i = 0; i < 2; i++)   // two status
        {if (i == 1){do_press(1,col);}deal_first_line(col + 1);if (i == 1){do_press(1,col);  //若状态已改变,恢复状态。因为同一个键按两次就会恢复原始状态
            }}}
}int main()
{int nTime;fp = fopen("in.txt","r");fscanf(fp,"%d",&nTime);nCase = 1;while (nCase <= nTime){memset(press,0,sizeof(press));memset(puzzl,0,sizeof(puzzl));input_data();deal_first_line(1);nCase++;}
}2013/4/24 22:01

标准答案中的代码很精简,但是我想不到。搜索的方法不只知道叫什么。。。

void enumate( )
{int c;bool success;for ( c = 1; c < 7; c++)press[1][c] = 0;while( guess() == false ) {press[1][1]++;c = 1;while ( press[1][c] > 1 ) {press[1][c] = 0;c++;press[1][c]++;}
}

当然,我的判断的那部分也写得太拙劣了。其实按后的灯光情况我们根本就不必去考虑。在枚举出第一行的press状态后,我们可以这样来判断,技巧很重要啊!

bool guess()
{int row,col;for (row = 1; row <= 4; row++ ){for (col = 1; col <= 6; col){press[row+1][col] = (puzzl[row][col] + press[row-1][col] + press[row][col] +press[row][col+1] + press[row][col-1]) % 2;}}for (col = 1; col <= 6){if (puzzl[5][col] != (press[4][col] + press[5][col] + press[5][col-1] + press[5][press+1]) % 2 ){return false;}}return true;
}2013/4/25 20:42

转载于:https://www.cnblogs.com/Jason-Damon/archive/2013/04/24/3041251.html

枚举--遍历搜索空间的例子:熄灯问题相关推荐

  1. 串口编程-枚举遍历串口、获取PC所有串口名称、遍历注册表项、RegEnumValue用法

    在网上找了几个关于遍历串口的例子,要么代码不完整,要么就有Bug,如读不了串口号大于10以上的.  经过本人的整理,现分享最终代码,vs2008下编译通过. //此方法同样适用于遍历windows开机 ...

  2. python中item是什么意思中文-Python中使用item()方法遍历字典的例子

    Python字典的遍历方法有好几种,其中一种是for...in,这个我就不说明,在Python了几乎随处都可见for...in.下面说的这种遍历方式是item()方法. item() item()方法 ...

  3. java enum判断_Java Enum枚举 遍历判断 四种方式(包括 Lambda 表达式过滤)

    packagecom.miracle.luna.lambda;importjava.util.Arrays;/*** @Author Miracle Luna * @Date 2019/6/9 23: ...

  4. 【CCCC】L2-008 最长对称子串 (25分),直接枚举遍历

    problem L2-008 最长对称子串 (25分) 对给定的字符串,本题要求你输出最长对称子串的长度.例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT& ...

  5. python同步枚举(遍历)两个list_拔剑-浆糊的传说_新浪博客

    1.方法1: 采用zip函数 names = ["zhang san","li si", "wang wu"] ages    = [18, ...

  6. php用栈遍历目录和文件,php如何遍历目录,php非递归算法遍历目录的例子

    function myscandir($pathname){ foreach( glob($pathname) as $filename ){ if(is_dir($filename)){ mysca ...

  7. python item方法_Python中使用item()方法遍历字典的例子

    Python字典的遍历方法有好几种,其中一种是for...in,这个我就不说明,在Python了几乎随处都可见for...in.下面说的这种遍历方式是item()方法. item() item()方法 ...

  8. Python中使用item()方法遍历字典的例子

    来源:http://www.jb51.net/article/54319.htm Python字典的遍历方法有好几种,其中一种是for...in,这个我就不说明,在Python了几乎随处都可见for. ...

  9. linux数组递增,shell 输入动态数组并遍历的简单例子

    [root@wzlvm shell]# cat shell_array_test.sh #!/bin/bash # # # # Aut wzl # Shell Document ## 判断是否传入参数 ...

最新文章

  1. java获取vdx文件数据_通过文件名获取文件类型ContentType
  2. 电脑快捷键横屏变竖屏,电脑显示器竖屏横屏来回切换怎么设置
  3. 10、MySQL锁等待,死锁,死锁检测
  4. Java中配置加密组件Bouncy_Castle
  5. mysql事务和锁InnoDB(转)
  6. 太极虚拟服务器,太极 中标 云服务器
  7. win7下装ubuntu14.04双系统
  8. Intellij idea安装JRebel插件 实现代码的热部署
  9. xshell 无法定位输入点_linux基础知识个人总结
  10. android qq毛玻璃,如何快速做出毛玻璃背景?有了这个网格渐变神器,1分钟搞定...
  11. 【web开发】js实现表单提交
  12. 【BZOJ4049】【Cerc2014】 Mountainous landscape 【凸包】【线段树】
  13. between and 用法
  14. hotmai邮箱服务器在境外吗,hotmail服务器如何设置?设置hotmail邮箱账号方法
  15. IDEA你可能不知道的小工具
  16. c语言实验内容.doc答案,C语言程序设计实验内容与答案.doc
  17. VMware Workstation虚拟机备份及磁盘空间回收
  18. php 计算百分比,百分比计算器
  19. python脚本案例-python+adb命令实现自动刷视频脚本案例
  20. Machine Learning 机器学习

热门文章

  1. Eclipse的ExtJs智能提示
  2. Java 基本功之(二)Java 面向对象
  3. 意法半导体STM32 ARM Cortex 32位微控制器
  4. 天问一号火星探测器已飞离地球800多万公里 多个载荷完成自检
  5. 智能驾驶继续突破,国内国外技术进入深水区
  6. 浙江金华暂时停用“智能头箍”,专家:监测学生脑电违反伦理
  7. 零基础如何入门深度学习?
  8. matlab作图如何改变坐标刻度
  9. Windows 32位程序在64位操作系统下运行
  10. 微信sdk服务器支付文档,微信支付-普通下单开发者文档