n*n數陣就是n*n魔方,要求每行每列及對角線之和都相等。下面是大學時用tc寫的乙個演算法,效率很高,找到所有4階需要16秒,剛才增加三行**消除對稱的魔方,只需2秒即可找到所有的832種可能(不輸出結果,只計數)。暫時還不知道標準答案,可能有遺漏或重複。
求解n階魔方,即將1、2、3…n*n放入n*n的矩陣中,使得每行每列及兩條對角線上的n個數的和都相等(等於sum=(n*n)*(1+n*n)/(2*n))。
主要演算法及思想:
首先得到所有的n個數的和為sum的組合情況,放在陣列all[m][n]中,其中每一組中的n個數都是從小到大排列,m為所有的組的個數。num[n*n]中存放了包含數字1、2…n*n的組的個數。index[m*n]中存放了包含1、2…n*n的組的序號(以此序號可在all中找到對應的n個數),其中單元1-num[1]中存放的是包含數字1的所有組的序號,單元num[1]+1-num[2]中存放了包含數字2的所有組的序號……。為方便得到包含任乙個數字n的所有的組的序號,構造一存放查詢偏移量的陣列offset[n*n],其中存放的是在index陣列中查詢包含任一數字的組的序號時的起始偏移量,如:要找包含數字n的所有組,可以從index陣列中offset[n]-offset[n]+num[n]單元得到組的序號,以此序號再到陣列all中得到組中的n個數字。
由於每乙個組中的數字都是從小到大排列的,要得到同樣n個數字的其他排列方式,可以通過函式rotat得到(n個數共有n!種排列方式)。
matrix[n][n]中存放的是n*n階矩陣的每乙個元素。得到魔方的步驟如下:
1。取一組的n個數字,按一種排列方式,放入矩陣的第一行。
2。取乙個包含第一行第一列中數字的組,按一種排列方式,放入矩陣的第一列。
3。取乙個包含第一行第二列中數字的組,按一種排列方式,放入矩陣的第二列:
每一列列中的每乙個數字(除第一行的),都要與同一行的已放置的數字可以在同乙個組中,如果是兩條對角線上的數字,還要考慮與已放好的對角線上的數字能存在於同乙個組中。如果不能滿足這個條件,則更換這一列的n的數字的排列方式,如果所有的排列方式都不行,則另選一組放入此列中,若所有的組的任一種排列方式都不能放入此列,則將前一列的n個數字換乙個排列方式,以此類推。
通過函式checkg(int group,int col)判斷第group組能否放入第col列中;通過函式checkr(int col)判斷將某一組按某一方式放入第col列後,已有的所有元素能否同時存在。
從以上的分析知,必須記錄第一行和每一列中放置的組的序號和排列方式,以便更改。這些資訊存放在陣列states[n+1][3]中,其中第一維表示第一行和n列,第二維的3個單元分別存放:組的序號,排列方式,在包含某一數字的所有組中的位置。
以下為n=3,m=8(sum=15)時的乙個例項分析:
all[8][3]:
0:1 5 9(該組的序號為0,用0表示該組)
1:1 6 8(該組的序號為1,用1表示該組)
2:2 4 9
3:2 5 8
4:2 6 7
5:3 4 8
6:3 5 7
7:4 5 6
三個數字的和為15的組合只有以上8中。
所有組中包含數字1的組有(用組的序號表示):0 1;包含數字2的組有:2 3 4;包含數字3的組有:5 6;……
num[9]: 2 3 2 3 4 3 2 3 2
index[24]:
(0 1)(2 3 4)(5 6)(2 5 7)(0 3 6 7)(1 4 7)(4 6)(1 3 5)(0 2)
(0 1)為包含數字1的組;(2 3 4)為包含數字2的組;(5 6)為包含數字3的組;……
offset[9]:0 2 5 7 10 14 17 19 22
如要找包含數字5的組,可在index中的10-10+4單元中找到組的序號0、3、6、7
(10=offset[5-1];4=num[5-1])
尋找魔方的步驟:
1。將第一組按第一種排列方式放入第一行,states[0][0]=states[0][1]=0;
1 5 9
0 0 0
0 0 0 (0表示還未放入數字)
2。考慮放入第一列:
找到包含數字1的所有組中的第乙個組(0:1 5 9),即states[1][2]=0;states[1][0]=0;
由於此組已經用於放在第一行中,不符合條件。
找到包含數字1的所有組中的第二個組(1:1 6 8),即states[1][2]++;states[1][0]=1;
此組符合條件,按第一種排列方式將6 8放入第一列states[1][1]=0;
1 5 9
6 0 0
8 0 0
由於副對角線上的8和9不能同時出現在乙個組中,不符合條件
按第二種排列方式將6 8放入第一列states[1][1]++;
1 5 9
8 0 0
6 0 0
副對角線上的6 9也不能同時出現在一組,不符合條件
由於沒有其他的排列方式,只能另選一組
包含數字1的組都不能滿足條件,故考慮更換第一行
3。將第一行中的n個數換一種排列方式:states[0][1]++;
1 9 5
0 0 0
0 0 0
4。考慮放入第一列:
states[1][2]=0;states[1][0]=0;此組已放入第一行
states[1][2]++;states[1][0]=1;states[1][1]=0;
1 9 5
6 0 0
8 0 0
5。考慮放入第二列:
找到包含數字9的所有組中的第乙個組(0:1 5 9),即states[2][2]=0;states[2][0]=0;
由於此組已用於第一行,不符合條件。
找到包含數字9的所有組中的第二個組(2:2 4 9),即states[2][2]++;states[2][0]=2;
按第一種排列方式states[2][1]=0;
1 9 5
6 2 0
8 4 0
由於主對角線上的1 2不能同時存在於一組中,不符合條件
states[2][1]++;
1 9 5
6 4 0
8 2 0
兩條對角線均不符合條件
包含數字9的組均不符合條件,考慮更換第一列
……最終找到乙個魔方:
6 1 8
7 5 3
2 9 4
乙個魔方矩陣的個人演算法
這樣乙個魔方矩陣 按以下示例方陣格式,生成乙個由自然數1至n 2組成的n階方陣。1 3 4 10 11 2 5 9 12 19 6 8 13 18 20 7 14 17 21 24 15 16 22 23 25 注 n不僅限於5。我的 include using namespace std defi...
線上診斷乙個load很高的問題
從監控系統中發現某集群的load很高,分析到最後發現是大量的disk io引起的。於是優化了上傳的元件不寫臨時檔案 發現io還是很高。再測試,竟然是apache的預設filter被改變後觸發了mod proxy的寫臨時檔案的條件,由於apache是寫死在 中的無法配置,於是將filter 重新註冊為...
LvClass 的乙個效率
前幾天,聽到了乙個客戶的抱怨 他編寫了乙個labview程式,每次開啟主程式就要花費幾分鐘的時間,這有點令他忍無可忍。我沒有見過他的源程式,不過據幫他檢查過程式的同事講,他的問題很可能是使用了大量的lvclass造成的。在他的專案中,包含有上百個類 lvclass 我以前也聽說過lvclass在效率...