国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

關(guān)燈游戲 Lights out (三)(線性代數(shù)+高斯消元,搜索全部解)

2019-11-11 06:35:29
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

        關(guān)燈游戲和線性代數(shù)聯(lián)系緊密,對(duì)于一個(gè) 的燈陣,用線性方程組+高斯消元法求解,時(shí)間復(fù)雜度為O(m×n)^3。相對(duì)于首行枚舉算法復(fù)雜度O(2^n) ,線代算法的時(shí)間復(fù)雜度低很多。用線性代數(shù)求解關(guān)燈游戲是個(gè)很不錯(cuò)的選擇。

        本文用最通俗的語(yǔ)言介紹線代求解關(guān)燈游戲原理。由于解釋通俗化,細(xì)節(jié)之處難以嚴(yán)謹(jǐn)表述,說(shuō)得不好的地方,請(qǐng)大神輕拍。

線性方程組求解關(guān)燈游戲的原理

問題:

        一個(gè)2×2燈陣,初始局面右下方3盞燈亮,左上角一盞燈不亮,如下圖所示。請(qǐng)用線性代數(shù)求解,找到可以使得所有燈都熄滅的開關(guān)操作。

解:

 %20 %20 %20 %20我們對(duì)四盞燈的開/關(guān)操作分別記為%20x1、x2%20、x3%20、x4%20,如下圖所示:

       我們用1代表操作,用0代表未操作,即 的取值為0或1。對(duì)四盞燈的亮/滅狀態(tài)分別記為 L1、L2 、L3 、L4 ,如下圖所示:

       我們用1代表亮著的燈,用0代表熄滅的燈,根據(jù)局面的初始狀態(tài),很顯然有

接下來(lái)觀察局面,

能影響L1燈的亮/滅狀態(tài)的操作只有 x1、x2 、x3 ;

能影響L2燈的亮/滅狀態(tài)的操作只有 x1、x2 、x4 ;

能影響L3燈的亮/滅狀態(tài)的操作只有 x1、x3 、x4 ;

能影響L4燈的亮/滅狀態(tài)的操作只有 x2、x3 、x4 ;

定理1:對(duì)同一盞燈開/關(guān)操作偶數(shù)次,等于操作0次;對(duì)同一盞燈操作奇數(shù)次,等于操作1次。

所以我們將 x1、x2、x3、x4 及其系取值限定在0或者1兩個(gè)數(shù)值,以后不再說(shuō)明(不怕蛋疼的話,可以對(duì)操作次數(shù)不限定,這樣一來(lái)將有無(wú)窮多個(gè)解,這些解都是在基礎(chǔ)解上對(duì)每盞燈再重復(fù)操作偶數(shù)次,本質(zhì)上相同)。

        假如一開始所有燈都熄滅,并且假設(shè)將 x1、x2、x3、x4 全體操作一遍后,燈陣的亮/滅狀態(tài)為當(dāng)前狀態(tài)。根據(jù)定理1,那么將 x1、x2、x3、x4 全體操作一遍,燈陣就又回到全熄滅狀態(tài)。x1、x2、x3、x4 就是我們想要的答案,于是列方程組:

       游戲問題轉(zhuǎn)換成了求解方程組問題。上面方程組不難求解,用初中的知識(shí)足夠了。有一點(diǎn)要注意,方程組是在二元域{0,1}內(nèi)求解,也就是運(yùn)算過程中,所有數(shù)值的取值范圍都只能是0或者1。二元域運(yùn)算規(guī)則和常規(guī)運(yùn)算規(guī)則有所不同,具體如下(不要問我二元域運(yùn)算規(guī)則為什么是這樣的,要問就問什么是燈?或者燈為什么會(huì)亮?之類的問題):

加法:0+0=0,0+1=1,1+0=1,1+1=0

減法:0-0=0,0-1=1,1-0=1,1-1=0

乘法:0×0=0,0×1=0,1×0=0,1×1=1

除法:0/0=無(wú)意義,0/1=0,1/0=無(wú)意義,1/1=1

        注:有限域上的運(yùn)算符號(hào)并不是上面那個(gè)樣子,而是一些圈、叉之類的奇怪符號(hào)。這里一方面不方便打出這些符號(hào),另一方面也為了讓讀者便于理解,所以仍舊采用“+、-、×、/”形式。我們看到,加減法都等價(jià)于二進(jìn)制位運(yùn)算中的“亦或”運(yùn)算;乘法等價(jià)于二進(jìn)制位運(yùn)算中的“與”運(yùn)算;除法在這里用不到,直接無(wú)視。

方程組求解結(jié)果為:

        這是方程組唯一的解,所以這個(gè)游戲局面解法是唯一的,標(biāo)記在游戲局面見下圖:

        到這里,線代原理就介紹完畢了。怎么樣,線代解法原理很簡(jiǎn)單吧,無(wú)非就是求解線性方程組問題。而計(jì)算機(jī)求解線性方程組,我們?cè)谠鰪V矩陣中用高斯消元法,時(shí)間復(fù)雜度為O(m×n)^3,判斷游戲有沒有解,可以用矩陣的秩來(lái)判斷方程組有沒有解,有多少個(gè)解。

用線性代數(shù)搜索所有解法的C/C++代碼如下:

#include<iostream>using namespace std;int Row,Column,MAXN;void init(int **matrix)                                            //初始化系數(shù)矩陣{	int i,j,k;	for(i=0; i<Row; i++)		for(j=0; j<Column; j++)		{			k=i*Column+j;			matrix[k][k]=1;			if(i>0)matrix[(i-1)*Column+j][k]=1;			if(i<Row-1)matrix[(i+1)*Column+j][k]=1;			if(j>0)matrix[i*Column+j-1][k]=1;			if(j<Column-1)matrix[i*Column+j+1][k]=1;		}}void  Gauss(int **matrix,int *solution)                            //高斯消元{	int i,j,k,x,y=0,rand_coefficient,rand_matrix,rank1,rank2,inc=0;	for(k=0; k<MAXN&&y<MAXN; k++,y++)                          //增廣矩陣轉(zhuǎn)換為階梯矩陣	{		x=k;		for(i=k+1; i<MAXN; i++)			if(matrix[i][y]>matrix[x][y])x=i;		if(x-k)                                            //交換矩陣行數(shù)據(jù)			for(j=y; j<MAXN+1; j++)			{				matrix[k][j]=matrix[k][j]^matrix[x][j];				matrix[x][j]=matrix[k][j]^matrix[x][j];				matrix[k][j]=matrix[k][j]^matrix[x][j];			}		if(matrix[k][y]==0)		{			k--;			continue;		}		for(i=k+1; i<MAXN; i++)                             //消元			if(matrix[i][y])				for(j=y; j<MAXN+1; j++)matrix[i][j]^=matrix[k][j];	}	for(rand_coefficient=rand_matrix=i=0; i<MAXN; i++)          //計(jì)算系數(shù)矩陣的秩和增廣矩陣的秩	{		for(rank1=rank2=j=0; j<=MAXN; j++)		{			if(j<MAXN)rank1|=matrix[i][j];			rank2|=matrix[i][j];		}		rand_coefficient+=rank1;		rand_matrix+=rank2;	}	if(rand_coefficient<rand_matrix)                            //系數(shù)矩陣秩小于增廣矩陣秩,局面無(wú)解		cout<<"此局面無(wú)解!/n/n";	else                                                        //枚舉并回代求解	{		for(k=1<<(MAXN-rand_coefficient); k>0; k--)		{			for(i=MAXN-1; i>rand_coefficient; i--)			{				matrix[i-1][MAXN]+=matrix[i][MAXN]>>1;				matrix[i][MAXN]&=1;			}			for(i=0; i<MAXN; i++)solution[i]=matrix[i][MAXN];			for(i=MAXN-1; i>=0; i--)                    //回代				for(j=i-1; j>=0; j--)					if(matrix[j][i])solution[j]^=solution[i];			for(i=0; i<MAXN; i++)                       //輸出答案				(i%Column)?cout<<solution[i]<<" ":cout<<endl<<solution[i]<<" ";			inc++;                                      //解數(shù)量計(jì)數(shù)器			PRintf("/n");			matrix[MAXN-1][MAXN]++;		}		cout<<"/n共計(jì)"<<inc<<"個(gè)解/n";	}}int main(void){	int i,j;	char C;	cout<<"/n                    關(guān)燈游戲(Lights out)解題程序(線代解法)/n";	cout<<"請(qǐng)輸入行數(shù):";	cin>>Row;	cout<<"請(qǐng)輸入列數(shù):";	cin>>Column;	MAXN=Column*Row;	int **matrix=new int*[MAXN+4];                            //增廣矩陣,二維數(shù)組	for(i=0; i<MAXN+4; i++)matrix[i]=new int [MAXN+4];	int *solution=new int[MAXN+2];                            //解數(shù)組	for(i=0; i<MAXN+4; i++)		for(j=0; j<MAXN+4; j++)matrix[i][j]=0;	init(matrix);                                             //初始化系數(shù)矩陣	cout<<"請(qǐng)選擇,是否輸入指定初始局面?(Y/N):",cin>>C;	if((C=='Y')||(C=='y'))	{		cout<<"請(qǐng)輸入初始局面(1代表亮燈,0代表滅燈,燈與燈之間用空格隔開,換行用回車):/n";		for(i=0; i<MAXN; i++)cin>>matrix[i][MAXN];	}	else for(i=0; i<MAXN; i++)matrix[i][MAXN]=1;              //默認(rèn)初始化局面為燈全亮  	Gauss(matrix,solution);	for(int i=0; i<MAXN+4; i++)delete []matrix[i];	delete []matrix;	delete []solution;	cout<<"/n/n求解完畢,請(qǐng)按任意鍵退出程序。";	cin.ignore(),cin.ignore();                                //暫停顯示	return 0;}    上面代碼可以搜索任意局面的全部解,允許用戶輸入任意初始局面,已經(jīng)非常方便使用了。如果還覺得使用上面代碼太麻煩,筆者將其制作成軟件,截圖如下:

軟件在這里下載:關(guān)燈游戲解題程序1.0版 https://pan.baidu.com/s/1geNMxcZ


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 马龙县| 滨海县| 海口市| 定日县| 清原| 温宿县| 鄢陵县| 宕昌县| 盘山县| 乌鲁木齐市| 博罗县| 太保市| 江达县| 繁峙县| 长葛市| 喜德县| 浪卡子县| 驻马店市| 岳西县| 台北县| 治县。| 杭锦旗| 东乌| 兴安盟| 台山市| 车险| 婺源县| 合江县| 都安| 祁连县| 常德市| 宜城市| 三门峡市| 绥阳县| 韩城市| 修武县| 九台市| 河池市| 平山县| 闽清县| 胶南市|