开灯关灯问题的两种解决方式

1.问题介绍
2.编程实现算法及其代码(详细)
3.就该题进行数学建模–体验线性代数的使用

1.问题介绍

有一个按钮组成的矩阵,其中每行有5个按钮,共5行。每个按钮旁边有一盏灯。当按下一个按钮,该按钮及其上下左右四个按钮控制的灯都会发生状态改变,即,如果灯原来是熄灭的,就会被点亮;如果灯原来是点亮的,就会被熄灭。(在矩阵角上的按钮会改变3盏灯的状)请写一个程序确定需要按下那些按钮,恰好使得所有灯都熄灭。

2.编程实现算法及其代码(详细)

1.解题思路

对于第一行每盏点亮的灯,按下第2行对应的按钮,就可以熄灭第1行的全部灯。如此重复下去,可以熄灭第1、2、3、4行的全部灯。同样,按下第1、2、3、4、列的按钮,可以熄灭前4列的灯。此时如果 第5行灯都是熄灭的 那么就得到了问题的解。有了基本思想以后,要解决两个问题:

1.对应的按钮
为了叙述方便,为按钮矩阵中的每个位置分别指定一个坐标。用数组元素 puzzle[i][j] 表示位置 (i, j) 上灯的初始状态:0表示灯的初始状态是熄灭的,1表示灯的初始状态是点亮的。用数组元素 press[i] [j] 表示为了让全部的灯都熄灭,是否要按下位置 (i, j) 上的按钮:1 表示要按下;0 表示不用按下。
因为灯的最后状态(按它下一行开关之前)与周围灯是否按按钮有关,如 puzzle[i] [j],决定它最后状态的相关按钮为 press[i] [j-1] (左),press[i][j](它本身),press[i] [j+1](右),press[i-1][j](上),还有它最初的状态 puzzle[i] [j]。考虑到按两次按钮作用会抵消,需要取它们的和与2的余数,所以puzzle[i] [j] 最后状态公式为:
puzzle[i][j]最后状态 = (press[i][j-1]+press[i][j]+press[i][j+1]+press[i-1][j]+ puzzle[i] [j] ) % 2
而press[i+1] [j](对应按钮) 由 puzzle[i] [j] 的最后状态决定,灯亮着(值为1)就要关掉它,press值取1,灯是熄灭的(值为0)不用处理,press值取0,它们是相等的,所以press[i+1] [j] = puzzle[i] [j] 最后状态。

2.验证第5行灯是否都熄灭
易知puzzle[5] [j] 的最终状态由按钮press[5] [j-1] (左),press[5][j](它本身),press[5] [j+1](右),press[4] [j](上)决定
当puzzle[5][j]为1时,即第5行j列灯亮着,则分为两种情况
(1). puzzle[5][j] 初始 =1,(press [5] [j-1] + press [5] [j] + press [5] [j+1] + press [4] [j])%2=0 即操作相互抵消
(2). puzzle[5][j]初始 =0,(press [5] [j-1] + press [5] [j] + press [5] [j+1] + press [4] [j]%2=1即操作不能抵消
注意这两种情况都是 puzzle[5][j]初始 !=press [5] [j-1] + press [5] [j] + press [5] [j+1] + press [4] [j]%2

由此可知, 当我们输入每一行的初始状态puzzle[i][j],并且枚举第一行的press[1][j]时,我们就可以根据解题思路得到一个可行解。

2.代码如下:(附有注释)

#include<stdio.h>
int press[6][8];
int puzzle[6][8];bool guess(){int i,j;for(i=2;i<=5;i++){for(j=1;j<=6;j++){// 根据同列的上一行灯的最后状态,来决定是否按按钮press[i][j] = ( press[i-1][j]+ puzzle[i-1][j]+ press[i-1][j-1]+ press[i-2][j]+ press[i-1][j+1] ) %2;}}for(j=1;j<=6;j++) {// 逐一判断第五行的灯是否都熄灭               if( puzzle[5][j] != (press[5][j] + press[5][j-1] + press[5][j+1] + press[4][j]) %2 )return false;}return true;
}void process() {int c;for(c=1; c<=6; c++)press[1][c]=0;while( !guess() ) {// 采用二进制进位的算法,从000000 - 111111枚举第一行按钮的方式press[1][1]++;c=1;                while(press[1][c]>1){press[1][c]=0;c++;press[1][c]++;}}
}int main(){int t,i,n,j;// 初始化0行的所有元素for(i=0;i<8;i++)press[0][i]=puzzle[0][i]=0;// 初始化0列,7列的所有元素for(i=1;i<6;i++)press[i][0]=puzzle[i][0]=press[i][7]=puzzle[i][7]=0;for(i=1;i<=5;i++)for(j=1;j<=6;j++)scanf("%d",&puzzle[i][j]);process();for(i=1;i<=5;i++){for(j=1;j<=6;j++){printf("%d ",press[i][j]);}printf("\n");}return 0;
}

这是我自己的理解,参照原文链接: https://blog.csdn.net/qianli_jiang/article/details/53420362?utm_source=app&app_version=4.5.2

3. 就该题进行数学建模——体验线性代数的应用

以下针对从全部熄灭到全部亮起的情况,0,1分别表示熄灭和亮着。 (在看以下内容前可以学习一下线性空间定义和线性空间中基,维数)
定义状态空间S为按钮矩阵上所有可能的状态组成的集合 ,即
S=(e1,e2,...,e25)∣ei=0,1,i=1,2,...,25S= {(e_1,e_2,...,e_{25}) | e_i=0,1, i=1,2,...,25} S=(e1​,e2​,...,e25​)∣ei​=0,1,i=1,2,...,25
显然灯全亮状态为s1s_1s1​={1,1,1…,1}∈\in∈S,全暗状态为s0s_0s0​={0,0,0,…0}∈\in∈S
定义S上的一个变换t :s=(e1,e2,...,e25)→s′=(h1,h2,...,h25),s,s′∈Ss=(e_1,e_2,...,e_{25}) \rightarrow s' =(h_1,h_2,...,h_{25}) , s,s'\in S s=(e1​,e2​,...,e25​)→s′=(h1​,h2​,...,h25​),s,s′∈S 其中hi=ei或者1−eih_i=e_i 或者1-e_ihi​=ei​或者1−ei​,特别的定义零变换为恒等变换
O(e1,e2,...,e25)=(e1,e2,...,e25)O(e_1,e_2,...,e_{25}) =(e_1,e_2,...,e_{25}) O(e1​,e2​,...,e25​)=(e1​,e2​,...,e25​)
设V是S上所有变换所组成的集合, 对任意f,g∈\in∈V,定义V中的加法运算为变换合成运算,记为f∘\circ∘g,并用∑\sum∑表示加法运算∘\circ∘的连加符号,例如:f1∘f2∘f3.....∘f25=∑i=125fif_1\circ f_2\circ f_3.....\circ f_{25}=\sum_{i=1}^{25}f_if1​∘f2​∘f3​.....∘f25​=∑i=125​fi​
容易验证该运算满足下列性质:


(1).f∘\circ∘g=g∘\circ∘f ∀\forall∀f,g∈\in∈V;
(2).(f∘\circ∘g)∘\circ∘t= f∘\circ∘(g∘\circ∘t); ∀\forall∀f,g,t∈\in∈V;
(3).对∀\forall∀f∈\in∈V,f∘\circ∘f=O

性质3告诉我们: 任何一种点击方式(变换)连续或间断操作偶数次,此操作的作用将被抵消,故为了使操作次数尽量少,应该避免重复操作。
为此考虑二元数域F2F_2F2​={0,1}(同一操作次数<=1) ,类似于实数域和有理数域,同样可以在F2F_2F2​进行加减乘除,运算法则如下:

+ 0 1
0 0 1
1 1 0
- 0 1
0 0 1
1 1 0
×\times× 0 1
0 0 0
1 0 1
÷\div÷ 0 1
0 无意义 0
1 无意义 1

那么我们可以定义二元域F2F_2F2​到V的数乘运算:1* f=f ,0*f=O, ∀\forall∀f∈\in∈V ,容易验证:

V是F2F_2F2​上的线性空间(8个性质)

将所有的方格按照从左到右从上到下依次编号为1到25,用gig_igi​,i=1,2,3,…25表示鼠标点击第i个方格所产生的变换,记一次可行的游戏策略为x(一个25维向量)=(x1,x2,....x25)T(x_1,x_2,....x_{25})^T(x1​,x2​,....x25​)T,其中xix_ixi​=0,1
则x满足: ∑i=125(xi∗gi)(s0)=s1\sum_{i=1}^{25}(x_i*g_i)(s_0)=s_1∑i=125​(xi​∗gi​)(s0​)=s1​ 关键是求出x.
为此定义变换fi∈Vf_i\in Vfi​∈V,i=1,2,…25为 fi(e1,e2,...,ei,...e25)=(e1,e2,...,1−ei,...,e25)f_i(e_1,e_2,...,e_i,...e_{25}) =(e_1,e_2,...,1-e_i,...,e_{25})fi​(e1​,e2​,...,ei​,...e25​)=(e1​,e2​,...,1−ei​,...,e25​)(神来之笔啊) 由定义知, fif_ifi​只会改变第i个方格的状态,而不会影响到别的方格, 容易得到{ fif_ifi​ |i=1,2,…25}是线性空间V的一组基,故gig_igi​可以唯一的用{fif_ifi​}表示为gi=fi∘fi−5∘fi+5∘fi−1∘fi+1g_i=f_i\circ f_{i-5}\circ f_{i+5}\circ f_{i-1}\circ f_{i+1}gi​=fi​∘fi−5​∘fi+5​∘fi−1​∘fi+1​,
化为矩阵形式为: (g1,g2,g3,...g25g_1,g_2,g_3,...g_{25}g1​,g2​,g3​,...g25​)=(f1,f2,f3,...f25f_1,f_2,f_3,...f_{25}f1​,f2​,f3​,...f25​)A25∗25A_{25*25}A25∗25​ …[1]
(由上式可知A25∗25A_{25*25}A25∗25​第i列只有第i-1,i-5,i+5,i+1,i-1行是1.可以根据这个写一下A,发现A可以表示成以下形式:A=HEOOOEHEOOOEHEOOOEHEOOOEH(1)A= \begin{matrix} H & E& O& O& O \\ E & H & E & O& O\\ O & E & H& E& O\\ O &O& E & H& E\\ O & O& O& E& H \end{matrix} \tag{1} A=HEOOO​EHEOO​OEHEO​OOEHE​OOOEH​(1) 其中每个矩阵都是5*5,E为单位矩阵,O为零矩阵,
H=1100011100011100011100011(1)H= \begin{matrix} 1 & 1& 0& 0& 0 \\ 1 & 1 & 1 & 0& 0\\ 0 & 1 & 1& 1& 0\\ 0 &0& 1 & 1& 1\\ 0 &0& 0 & 1& 1 \end{matrix} \tag{1}H=11000​11100​01110​00111​00011​(1)将[1]代入得: ((f1,f2,f3,...f25f_1,f_2,f_3,...f_{25}f1​,f2​,f3​,...f25​)A25∗25A_{25*25}A25∗25​x)(s0s_0s0​)=s1s_1s1​
而(f1,f2,f3,...f25f_1,f_2,f_3,...f_{25}f1​,f2​,f3​,...f25​)(1,1,1,...,1)T(1,1,1,...,1)^T(1,1,1,...,1)T=s1s_1s1​,故 A25∗25A_{25*25}A25∗25​x=(1,1,1,...,1)T(1,1,1,...,1)^T(1,1,1,...,1)T
当这个方程有解,这些灯才能由暗全部亮起,否则不可能达到目标,至于解方程,注意因为这个x向量只能由0,1组成,所以解方程时不能直接走常规路线,具体可以参考抽象代数的书籍(笔者能力有限,请谅解)。
这是我写的第一篇文章,有很多不足之处,希望大家多多理解,不当之处请指正,谢谢!最后希望读者可以从这篇文章体会细心线性代数的应用,理解思想,加油!

开灯关灯问题的两种解决方式(数学建模线性代数的应用和编程实现)相关推荐

  1. chrome拦截弹窗问题的两种解决方式

    chrome拦截弹窗问题的两种解决方式 参考文章: (1)chrome拦截弹窗问题的两种解决方式 (2)https://www.cnblogs.com/CaiDaili/p/9228455.html ...

  2. redis连接不上,两种解决方式

    今天某个项目的redis连不上了,将自己用到的两个解决办法写篇记录(实际使用时方法二选一即可). redis连接不上,两种解决方式 一.首先排查本地redis连接有没有问题 1. 在服务器上查看red ...

  3. 我的世界 服务器内切换账号密码是多少,我的世界OP查询玩家账号密码 两种解决方式...

    我的世界OP查询玩家账号密码 两种解决方式.我的世界服务器中OP想要查询玩家账号登录密码也不是不可以的,但是一般需要插件协助才能完成.目前两种方式可以实现密码查询. 我的世界服务器OP怎么查询玩家密码 ...

  4. hdfs——Attempting to operate on hdfs namenode as root 两种解决方式

    root用户启动报错: ERROR: Attempting to operate on hdfs namenode as root ERROR: but there is no HDFS_NAMENO ...

  5. 自动弹窗被拦截 html,chrome拦截弹窗问题的两种解决方式

    在前端编写中,可能会用到window.open,等方式来在新的tab打开url.但会发现,有些情况下新打开的tab页会被chrome拦截了: 出现这种情况,很有可能是因为:这些调用不是由用户行为(如: ...

  6. 468,提莫攻击的两种解决方式

    想了解更多数据结构以及算法题,可以关注微信公众号"数据结构和算法",每天一题为你精彩解答.也可以扫描下面的二维码关注 问题描述 在<英雄联盟>的世界中,有一个叫 &qu ...

  7. Python爬虫开发:url中文字符编码的两种解决方式

  8. 文本框和按钮对不齐的两种解决方式html

    方式一: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  9. Vite内网ip访问,两种配置方式

    问题 使用vite运行项目的时候,控制台会只出现127.0.0.1(localhost)本地地址访问项目.不可以通过公司内网ip访问,其他团队成员无法访问,这是因为没有将服务暴露在局域网中: 两种解决 ...

最新文章

  1. GAN(Generative Adversarial Network,GAN)模型之:SeqGAN、IRGAN、StackGAN、BigBiGAN、GAIN模型
  2. 第一次spring,第三天。
  3. PHP学习笔记4:字符串与正则
  4. Redis 是属于多线程还是单线程?
  5. php redis删除所有key,php redis批量删除key的方法
  6. 栅格布局一般怎么用_建筑混凝土色差大怎么办?用这种方法处理,一般都看不出来...
  7. 年度总结 | 小小的年度大总结!太精辟!
  8. Java获得中文输入_使用java简单实现根据输入的汉字,得到汉字的首字母
  9. 【Python】pymysql.err.InternalError: (1236, 'Misconfigured master - server_id was not set')
  10. python 地理处理包:geopandas介绍
  11. 七牛云:ckeditor JS SDK 结合 C#实现多图片上传。
  12. 手游:cocos2d-x3.0 移植 wp8 开发 各种 “蛋疼”问题的汇总
  13. 中文核心期刊是什么?
  14. 类似endnote_Mendeley与EndNote类似的免费文献管理软件简介 | 科研动力
  15. safari 插件(如Xmarks)的设置、登陆、禁用等
  16. 【模式串匹配】Aho-Corasick algorithm - AC字符串匹配算法实现与测试【Python】
  17. 寄存器(RAL)模型中的write方法
  18. (已更新)Discuz手机模板:NVBING5-APP手机版,界面美观大方,可封装安卓/苹果APP,模板文件+插件+分类信息导入文件
  19. 一篇文章搞懂Typescript
  20. 计算机实训报告思路,计算机实训报告优秀范文

热门文章

  1. New York City Airbnb Open Data(纽约市Airbnb开放数据集)
  2. 我的JAVA笔记--线程
  3. 每日一课 | Python数据可视化—多样化的图像
  4. ACS724LLCTR-30AB-T优点
  5. React native ios上架
  6. 罗技M545鼠标失灵起死回生
  7. 商业数据分析之行业研究
  8. 省钱购物app排行榜!
  9. Qt编写自定义控件12-进度仪表盘
  10. 03、【solidworks】solidworks启动很慢,正在加载插件3DEXPERIENCE