[UVA10181]十五數碼解題報告


對於有解的情況,只需ID-A*即可。
首先談一談估價函數,估價函數表示的應該是對期望步數的下界。我一開始想的是用所有數現在的位置到應該在的位置的曼哈頓距離和,考慮到一次交換最多令其減少2,所以還要把它除以2。后來看了題解發現所有題解都是用的所有非0數的現在的位置到目標位置的曼哈頓距離和,這樣的話一次交換最多令其減少1,這樣應該是比較合適的。。
我一開始寫的A*,(因為沒有看懂ID-A*)A*需要面對map判重、heap維護,空間復雜度與時間復雜度相同,且掛了log的常數,時間空間都不占優。
后來終於看懂了ID-A*,ID-A*為什么不用判重?是因為我們考慮搜索樹中的一個節點,如果它(假設我們做一個簡單的剪枝、拒絕反着走到達當前狀態的最后一步)被再次搜到,就意味着它至少又轉了四下。也就是說一個點至多被搜 50413 ,即其常數約為13!也就是說這其實是比用平衡樹判重快得多的。但是ID-A*是不能像A*一樣每次取出預估最優的狀態的,它只能通過調整上下來解決這個問題;這跟DFS與ID-DFS的區別還不一樣,因為在一個預估較劣的狀態可能會達到一個預估較優的狀態。所以實際上ID-A*與A*的區別還是很大的,它實際上並不是A*的簡單優化;它也並不一定比A*跑得更快,如果你的估價函數不是很准的話。。

其實這個題更有意思的地方,在於對於無解的判斷。
我在網上並沒有找到關於15數碼的完整證明,不過有8數碼的,但是我似乎並不能把它推廣到15數碼甚至是N*M數碼。但是我前前后后研究了差不多有4個月,在這里將會給出一個嚴謹的證明。
命題:
在一個N*M( N>1,M>2 )的矩陣中,我們放入0~N*M-1的排列,稱之為數碼。
我們允許兩種操作,一種是將0與其所在的格子左右相鄰的格子里的數互換,一種是將0與其所在的格子上下相鄰的格子里的數互換。

當M為奇數時,兩種數碼可以互達與兩種數碼【排列逆序對數(不算0)】奇偶性相同等價。
當M為偶數時,兩種數碼可以互達與兩種數碼【排列逆序對數(不算0)+0的縱坐標】奇偶性相同等價。

證明:
首先證明兩種數碼可以互達當且僅當……(后面那一串)
考慮0左右移動,顯然不會改變不算0的排列的逆序對數;而上下移動的話,考慮增量,就相當於是有M-1個數,每個數∈{-1,1},問其和?在模2意義下,-1≡1,所以其實它們的和在模2意義下恆等於M-1.
那么接下來的事情就很顯然了,其實這個玩意兒本身就是構造的,奇數的時候不用管它,反正M-1≡0(mod 2);偶數的時候,上下移動0的縱坐標就會+1或-1,所以再加上0的縱坐標的話,奇偶性就不會變了。

好!接下來就是真正的核心部分了!(我可是玩了很久才玩出規律的。。)
由於兩個數碼之間的變換是可逆的,現在所有的數碼都分為了兩類,所以如果我們能證明出所有的數碼都能變換到兩個數碼之一,那么就好了!
我們選擇將所有數碼變換成類似這種形狀:

但是我們該怎么做呢?
首先我們看一下前人對八數碼的研究(因為由於排版造成的問題。。我進行了一些修改。):

轉載自【水木清華BBS精華區】:http://www.cnw3.org/smth/AI/5/8/00000001.htm

發信人: YourMajesty (花痴~~~~小魔男), 信區: AI
標 題: 關於八碼數問題有解與無解的證明(zz)
發信站: BBS 水木清華站 (Fri Nov 23 22:26:49 2001)

我們將九宮格按行排成一行共九個數(空格也占一個位置,在本文種,我用@表示空 格)。比如:
1 2 3
4 @ 5 => 1 2 3 4 @ 5 6 7 8 這樣
6 7 8
,九宮格的每一種狀態和上圖的行之間是一一對應的。
為了證明上述定理,我想先對問題進行一下轉化。我定義兩種行序列的變換:一種是空格@和相鄰的數對換,一種是空格@和前后隔兩個數的數之間的對換(按:或是從這一行的行首到上一行的行末),前者對應着空格在九宮圖中的左右移動,后者對應着空格在九宮圖中的上下移動。
引理一:在上述的兩種對換下,序列的奇偶性不改變。 這個引理很容易證明。
首先,相鄰的對換肯定不改變奇偶性;其次,隔兩格的對換也不改變奇偶性,它相當於三個數的輪換。這就說明了奇九宮圖和偶九
宮圖之間是互不可達的。
引理二:轉化后行序列在上面定義的兩種對換下的任意操作,可以轉換成九宮圖中 空格的合法變化。 這個引理也是比較容易證明的。我們只要證明如下的兩種狀態之
間是互達的:
1 2 3             1 2 3
4 5 6<=>4 5 @
@ 7 8           6 7 8
通過計算機搜索,可以發現上面兩種狀態之間的確是互達的。(按:我們其實也可以構造,使用與后面類似的方法。將數成對豎着排起來即可。由於非常簡單而且我不會推廣到高維。。這里略去不詳細說明)從而,我們可以假定上面兩種狀態之間的轉換可以用行序列中的兩種鄰對換來代替。
引理三:所有的奇狀態可以轉換為 @ 1 2 3 4 5 6 7 8, 所有的偶狀態可以轉換為 @ 2 1 3 4 5 6 7 8. 要證明這個引理,得分幾個步驟。我的想法是先設法把8移到最后一個,然后8保持不動(注意,我們這里的不動只是形式上不動,但不管怎樣,我們的每一個變換后,8還是保持在最后一個,余類似),再將7移到8之前,然后, 保持7和8不動,依次移動6,5,4,3,得到 * * * 3 4 5 6 7 8這里 * * *是 @ 1 2 的一個排列。到這里,我想要得到前面的兩種狀態之一是顯然的了。下面,我說明,上面的想法是可以實現的。如下:
1. 對於 a b c @ ,我們可以將其中的任意一個移到
最后,並且對變換僅限於這四個位置上。顯然,對於a,c是一步就可以做到的。對於b, 步驟如下: a b c @ -> @ b c a -> b @ c a -> b c @ a -> b c a @ -> @ c a b
2. 先把要移到最后位置的那個數移到最后四個位置之一,然后再將空格移到最后一個位置,用1的方法將待移動的數變換到最后一個位置。循環這樣做即可。引理三證畢。
證完了這三個引理,定理的成立就是顯然的了。首先,將奇偶性相同的兩種狀態都變換到上述兩種標准狀態之一,然后對其一去逆變換即可。

我們知道M=5與M=3是相似的,但是我感覺這個證明如果往M=5的情況推廣的話,會遇到很大問題啊。因為這樣的話最終它需要面臨的就不再是1~2的排列了,而是1~4的排列。。然而我們卻希望把它們划歸到兩種狀態。

所以我們需要引入新的算子。
在研究15數碼的時候,我發現了這樣一件事情!其實我們可以把一行旋轉,比如對於
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 0
它可達
1 2 3 4
5 6 7 8
9 10 11 12
15 13 14 0
而3個數的排列只有6種,也就是說如果只有最后3個數不同而奇偶性,那么我們可以將其旋轉使其相同。
這是非常重要的一點,下面我想具體地說明一下這是怎么實現的。
其基本思路就是把數成對成對地豎起來。
0、
1 2 3 4
5 0 6 7
1、
1 0 3 4
5 2 6 7
2、
5 1 3 4
0 2 6 7
3、
5 1 3 4
2 0 6 7
4、
5 0 3 4
2 1 6 7
5、
0 5 3 4
2 1 6 7
6、
2 5 3 4
0 1 6 7
7、
2 5 3 4
1 0 6 7
8、
2 5 3 4
1 6 0 7
9、
2 5 3 4
1 6 7 0
10、
2 5 3 0
1 6 7 4
11、
2 5 0 3
1 6 7 4
12、
2 0 5 3
1 6 7 4
13、
2 6 5 3
1 0 7 4
14、(看!它們都豎起來了!)
2 6 5 3
1 7 0 4
15、
2 6 0 3
1 7 5 4
16、
2 6 3 0
1 7 5 4
17、
2 6 3 4
1 7 5 0
18、
2 6 3 4
1 7 0 5
19、
2 6 3 4
1 0 7 5
20、
2 0 3 4
1 6 7 5
21、
0 2 3 4
1 6 7 5
22、
1 2 3 4
0 6 7 5
這其實意味着我們可以令一個數跳過兩個數,我們稱之為跳躍算子。
好嘞!現在讓我們來試圖划歸一個N*M的數碼。
這里,我們約定M>3,當M=3時。。是與八數碼的證明相同的。(而我下面的證明卻不能解決這種情況。。)
在下面的說明中,我們選擇忽視0,因為0在左右移動的時候不會影響其他數的相對位置。
一、前N-2行。
首先我們對付前M-2列,這是易行的,只需要不斷把空格繞道待操作數期望路線上就可以了;
對於最后兩列,假如說這一行最后兩個數是3、4,那么就先把4放到倒數第二列,然后把3放到下一行倒數第二列,然后把0放到這一行最后一列,然后把0左移、下移!
…… 4 0
…… 3
=>
…… 0 4
…… 3
=>
…… 3 4
…… 0
二、第N-1行。
注意到跳躍算子實際上是一行內的操作,如果我們規定一個數的坐標x(a)表示a的位置之前(一行內)有幾個非0數,那么對於一個數而言,跳躍算子就是在把其坐標+2或-2的操作。
那么實際上我們就可以把一個數移動到任意一個坐標了!
因為我們可以首先對其不斷使用跳躍算子,直到它的坐標與目標坐標之差的絕對值小於2;這時,如果它的坐標與目標坐標還差1的話,我們便可跳躍它周圍的數,使之抵達目標坐標。這樣做的正確性是顯然的,因為使一個后面的數到前面去或是使一個前面的數到后面去會使當前的數的坐標+1或-1.
但是這樣做是有條件的,它的條件是這一行至少有三個數(這個很顯然吧)。

所以,我們順序前M-2列,把待操作的數移到最后一行,然后使用跳躍算子把它移到期望位置的下面,然后把0移到它上面,然后把0移下來即可。
然后使用類似的方法,把倒數第一個數移到倒數第二個位置上,把倒數第二個數移到最后一排的最后,然后把0移到最后(這樣它就在倒數第二個位置上了),然后把0移上去,向對付前幾行那樣轉一下即可。
這樣我們就只需處理最后一行了。
三、第N行。
注意我們剛剛得出的結論,使用跳躍算子可以把一個數移到任意坐標!而它的
那么接下來該做的事情就幾乎是顯而易見了,假如說最后我們應該把M-1~1排出來(當然這是不可能的,不過我們可以把我們需要做的排列完全等價地映射到這上面去),那么我們就可以先把M-1放到第一個位置,然后保持其不動,把M-2放到第2個位置。。依次操作,直到——直到還剩兩個數!而兩個數的排列只有兩種!
於是,我們便可把所有排列映射到兩個排列之一,原命題得證!
命題:
在一個N*M( N>1,M>2 )的矩陣中,我們放入0~N*M-1的排列,稱之為數碼。
我們允許兩種操作,一種是將0與其所在的格子左右相鄰的格子里的數互換,一種是將0與其所在的格子上下相鄰的格子里的數互換。

當M為奇數時,兩種數碼可以互達與兩種數碼【排列逆序對數(不算0)】奇偶性相同等價。
當M為偶數時,兩種數碼可以互達與兩種數碼【排列逆序對數(不算0)+0的縱坐標】奇偶性相同等價。

讓我們再來做一些有趣的擴展!
考慮對於a*b*c(a>2,b>2,c>2)的長方體,它里面有0~a*b*c-1,是一個像平面數碼一樣的立體數碼,然后0在里面到處亂轉。那么它的有解無解情況又該是如何呢?
顯然結論是,若以a為縱坐標長度,b為橫坐標長度,c為高度,考慮把每一個平面順次展開的排列的逆序對,則我們加上0的縱坐標當且僅當b為偶數,我們加上0的高度當且僅當a*b為偶數。
證明的話也是容易的,考慮在z軸上移動會有a*b-1個+1或-1,在y軸上移動會有b-1個,在x軸上移動不會改變逆序對。
我們從上到下順次處理每一個平面,大可直接把當前平面位置需要的數直接移到它z軸-1的位置,然后讓0從x軸-1或y軸-1的位置過去,就可以了;然后處理一下最后兩個數,先把倒數第一個數放到倒數第二個數的位置,然后把倒數第二個數放到它z軸-1的位置,然后讓0上去轉一圈就好了。這樣還剩最后一個平面,就是正常的平面數碼問題了。(這樣看來。。其實立體數碼問題要比平面數碼問題簡單多啊!)

回顧一下我是怎么解決十五數碼問題的,對於有解的情況,我選擇了A*和ID-A*算法,我發現:
對於特殊點,我可以對它做特殊處理往往會有更好的效果!(我那傻逼的估價函數啊。。)
對於無解的情況,我首先得到了結論。然后我試圖證明它,在百思不得其解以后參閱了八數碼問題的無解證明,並受之啟發。
應用了可逆性、歸一法、排列的映射等多種有趣的性質!終於完成了N*M數碼的證明。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com