沒有辦法,迫於興趣,只好對以前寫過的八數碼問題進行重寫,這次重寫(A*依舊使用原來的估價方式估價)着重考慮 數據結構 的, 來提高執行效率。
通過測試,現在的八數碼,執行效率還不錯。 在此,把代碼提供出來,一起學習~~ 不過,我把其寫在同一個.cpp中(雖然這麼做,不合理,但是我還是這麼做了~) 該程序中:1:採用棋盤壓縮 2:hash表判重 3: 路徑記錄通過hashtable中回溯 4:優先隊列 用堆實現
源代碼如下(代碼調試運行平臺爲:Microsoft Office 提供的 VC++6.0 編譯器):
#include <memory.h>
#include <windows.h>
#define HashTableSize 260441 // 562147 460387 400249 360323 260441
#define HeapSize 5000
#define MaxSteps 100
/**//*** 經過從 1 2 3 4 5 6 7 8 0 到 0 8 7 6 5 4 3 2 1 枚舉測試,
各個素數(HashTableSize) 的 hash 查詢次數和表使用率如下:
素數 平均查詢次數 使用率
562147 1.22 32.3%
460387 1.28 39.4%
400249 1.36 45.3%
360323 1.41 50.4%
260441 1.75 70.0%
*/
/**//***
這個棋盤採用4個字節表示。
其中 空格, 以及對應的 1~ 8 的數字, 用三個位表示, 然後 用四個位表示 空格的位置
(這共花了 3 * 9 + 4 = 31 個位 )。
注意棋盤是按 從上到下,從左到右, 依次標上編號:
--------------
| 00 | 01 | 02 |
--------------
| 03 | 04 | 05 |
--------------
| 06 | 07 | 08 |
--------------
棋盤表示法:
000 : 1 , 001 : 2 , 010 : 3
011 : 4 , 100 : 5 , 101 : 6
110 : 7 , 111 : 8 , 000 : 空格.
注意: 有的這裏 空格的位置 和 數碼 1 的編碼是一樣,這並不矛盾, 因爲實際上 空格編碼可以刪除,
因爲 後面要用 4 個位記錄空格位置。 那麼爲什麼還給 空格編碼呢? 這主要是對壓縮棋盤的上下左右
移動更加方便。
例如: 在 對下 棋盤:
6 8 3
0 5 2
4 7 1
那麼對應的Reduce_Map 編碼是: 101 111 010 000 100 001 011 110 000 0011 0
--- --- --- --- --- --- --- --- --- ---- ---
6 8 3 空格 5 2 4 7 1 3 標誌位
*/
/**//*** 棋盤數據結構 ****/
typedef struct reduce...{
public:
unsigned a00: 3 , a01: 3 , a02: 3 ;
unsigned a03: 3 , a04: 3 , a05: 3 ;
unsigned a06: 3 , a07: 3 , a08: 3 ;
unsigned empty: 4 ; // 記錄 空格的位置.
unsigned used: 1 ; // 在 HashTable 元素中該位用來表示,是否已經佔了。
reduce():used(0)...{}
bool operator == (const reduce& a);
}Reduce_Map ;
/**//**棋盤的表示**/
typedef struct ...{
public:
unsigned __int8 Board[9];
unsigned __int8 empty ;
void print()
...{
for(int i =0 ; i < 9 ; i ++ )
...{
if(i%3 == 0 ) printf(" ");
printf("%5d",Board[i]);
}
}
}Map ;
/**//*****搜索的節點的表示******/
struct Nodes...{
public:
Reduce_Map RMap ;
unsigned __int8 gx ;
unsigned __int8 fx ;
// unsigned short hx ; // hx = fx - gx ;
unsigned int parent ; // 父節點, 在hash表中的位置
unsigned int index ; // 該節點在hashtable中的位置
Nodes():gx(0),fx(0)...{}
void Evaluate()...{}
};
/**//***棧:用來記錄路徑**/
struct stacks...{
public:
__int8 length ;
Reduce_Map path[MaxSteps];
stacks():length(-1)...{}
void push(Reduce_Map& temp)...{ path[++length] = temp; }
Reduce_Map pop()...{ return path[length--] ; }
}Stack;
/**//****hash表****/
struct hashtable...{
Reduce_Map status ;
int PreIndex ; // 用來記錄 該節點的父節點在HashTable中對應的位置。
}HashTable[HashTableSize];
/**//****優先隊列******/
struct PriorityQueue
...{
public:
Nodes Heap[HeapSize]; // 堆數組
int bear ; // 堆長度
PriorityQueue():bear(-1)...{}
Nodes pop();
void push(Nodes);
void print();
bool empty()...{ return (bear== -1);}
}Queue;
void inline swap(Nodes& , Nodes&);
bool inline compare(const Nodes& , const Nodes&);
/**//*** 重載 == 運算符*****/
bool reduce::operator ==(const reduce& a)
...{
static Reduce_Map temp ;
temp = a ;
temp.used = this->used ;
if( memcmp( this , &temp , 4 ) == 0 ) return true ;
return false ;
}
void PriorityQueue::push(Nodes temp)
...{
Heap[++bear] = temp ;
int k = bear, p ;
while(k)
...{
p = (k - 1 )>>1;
if( compare( Heap[k],Heap[p]) ) return ;
swap(Heap[k],Heap[p]);
k = p ;
}
return ;
}
Nodes PriorityQueue::pop()
...{
int flage , k = 0 , p ;
swap(Heap[0],Heap[bear--]);
while( ( p = ( k << 1 ) ) < bear )
...{
flage = 1;
if( ( (p + 1) < bear ) && compare( Heap[ p + 1 ] , Heap[ p + 2 ] ) ) flage ++ ;
if(compare( Heap[ p + flage ] , Heap[k] ) ) break ;
swap(Heap[ p + flage] , Heap[k]);
k = p + flage ;
}
return Heap[bear+1];
}
void PriorityQueue::print()
...{
for(int i =0 ; i <= bear; i ++ )
printf(" fx:%d hx:%d ",Heap[i].fx , Heap[i].fx-Heap[i].gx);
printf(" ");
getchar();
}
/**//**方格中不同位置之間的距離**/
static unsigned __int8 Steps[9][9]=...{
...{ 0 , 1 , 2 , 1 , 2 , 3 , 2 , 3 , 4 } ,
...{ 1 , 0 , 1 , 2 , 1 , 2 , 3 , 2 , 3 } ,
...{ 2 , 1 , 0 , 3 , 2 , 1 , 4 , 3 , 2 } ,
...{ 1 , 2 , 3 , 0 , 1 , 2 , 1 , 2 , 3 } ,
...{ 2 , 1 , 2 , 1 , 0 , 1 , 2 , 1 , 2 } ,
...{ 3 , 2 , 1 , 2 , 1 , 0 , 3 , 2 , 1 } ,
...{ 2 , 3 , 4 , 1 , 2 , 3 , 0 , 1 , 2 } ,
...{ 3 , 2 , 3 , 2 , 1 , 2 , 1 , 0 , 1 } ,
...{ 4 , 3 , 2 , 3 , 2 , 1 , 2 , 1 , 0 }
};
/**//**兩中目標狀態***/
static unsigned __int8 DlTarget[2][8]=...{
...{ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 },
...{ 0 , 1 , 2 , 5 , 8 , 7 , 6 , 3 }
};
static __int8 Derection[4] = ...{ 1 , -1 , 3 , -3 } ;
//static char DeToChar[4] = {'r', 'l','d', 'u'} ;
/**//******目標狀態********/
static unsigned __int8 Target[8] ;
bool inline compare(const Nodes& Nodes1, const Nodes &Nodes2)
...{
if(Nodes1.fx > Nodes2.fx) return true ;
if(Nodes1.fx < Nodes2.fx) return false;
return(Nodes1.gx < Nodes2.gx);
}
void inline swap(Nodes& a , Nodes&b)
...{
Nodes c = b ;
b = a ;
a = c ;
}
/**//*** 棋盤的壓縮**/
inline void ReduceTheMap(Map& IMap , Reduce_Map& RMap )
...{
IMap.Board[IMap.empty] ++ ;
RMap.a00 = IMap.Board[0] - 1 , RMap.a01 = IMap.Board[1] - 1 , RMap.a02 = IMap.Board[2] - 1;
RMap.a03 = IMap.Board[3] - 1 , RMap.a04 = IMap.Board[4] - 1 , RMap.a05 = IMap.Board[5] - 1;
RMap.a06 = IMap.Board[6] - 1 , RMap.a07 = IMap.Board[7] - 1 , RMap.a08 = IMap.Board[8] - 1;
RMap.empty = IMap.empty ;
IMap.Board[IMap.empty] -- ;
return ;
}
/**//*** 棋盤的解壓**/
inline void UnreduceMap(Map& IMap , Reduce_Map& RMap)
...{
IMap.Board[0] = RMap.a00 + 1 , IMap.Board[1] = RMap.a01 + 1 , IMap.Board[2] = RMap.a02 + 1 ;
IMap.Board[3] = RMap.a03 + 1 , IMap.Board[4] = RMap.a04 + 1 , IMap.Board[5] = RMap.a05 + 1 ;
IMap.Board[6] = RMap.a06 + 1 , IMap.Board[7] = RMap.a07 + 1 , IMap.Board[8] = RMap.a08 + 1 ;
IMap.empty = RMap.empty ;
IMap.Board[IMap.empty] -- ;
return ;
}
/**//*** 判斷是否查找過了(使用雙散列函數探測法),
函數返回該節點在hashtable中的位置,
如果返回值爲:-1 表示已經存在
*/
int InsetHashTable( Reduce_Map RMap , int PreIndex = -1 )
...{
unsigned int Code;
__asm // 彙編實現同字節不同類型值的賦值: Code = RMap
...{
mov eax,dword ptr[RMap]
mov dword ptr[Code] ,eax
}
Code %= HashTableSize;
if(HashTable[Code].status.used == 0 ) // 如果used 爲 0 ,表示 該處未被佔用
...{
HashTable[Code].status = RMap ;
HashTable[Code].status.used = 1 ;
HashTable[Code].PreIndex = PreIndex ; // 記錄父節點在hashtable中的位置,便於回溯找路徑
return Code ;
}
if( HashTable[Code].status == RMap ) return -1 ;
unsigned int temp = Code | RMap.empty; // 經過測試,這樣簡單操作後,使得二次探測碰撞減少了些~~
while(HashTable[Code].status.used == 1 )...{
Code += temp ;
if(Code >= HashTableSize) Code -= HashTableSize ;
if( HashTable[Code].status == RMap ) return -1 ;
}
HashTable[Code].status = RMap ;
HashTable[Code].status.used = 1 ;
HashTable[Code].PreIndex = PreIndex ;
return Code ;
}
/**//***對 hx 的估價(使用的是: 每個數碼到目標位置的距離 之和 ) ***/
inline void Evaluate(Nodes& one)
...{
one.fx = - Steps[ one.RMap.empty ][ Target[ 0 ] ] ;
one.fx += Steps[ 0 ][ Target[ one.RMap.a00 ] ] + Steps[ 1 ][ Target[ one.RMap.a01 ] ] +
Steps[ 2 ][ Target[ one.RMap.a02 ] ] + Steps[ 3 ][ Target[ one.RMap.a03 ] ] +
Steps[ 4 ][ Target[ one.RMap.a04 ] ] + Steps[ 5 ][ Target[ one.RMap.a05 ] ] +
Steps[ 6 ][ Target[ one.RMap.a06 ] ] + Steps[ 7 ][ Target[ one.RMap.a07 ] ] +
Steps[ 8 ][ Target[ one.RMap.a08 ] ] ;
one.fx += one.gx ;
}
/**//****回溯找出路徑***/
void FindFinalPath(unsigned int& ObjIndex )
...{
int temp = ObjIndex ;
while(temp != -1 )
...{
Stack.push(HashTable[temp].status);
temp = HashTable[temp].PreIndex;
}
return ;
}
void search(Nodes begin )...{
Nodes one , now ;
int temp , flage ;
Queue.push(begin);
while( !Queue.empty() )...{
now = Queue.pop();
if(now.gx == now.fx )
...{
FindFinalPath(now.index);
return ;
}
for(int k =0 ; k < 4; k ++ )
...{
temp = now.RMap.empty + Derection[k] ;
if(temp >=0 && temp< 9 && Steps[temp][now.RMap.empty] == 1 )
...{
one.RMap = now.RMap ;
one.RMap.empty = temp;
__asm // 由於這裏RMap 被定義爲struct 類型, 因此移動很不方便,所以只好採用彙編了
...{
; 把one.RMap.empty 空格的位置取出(即移動後 空格所在位置)
mov ecx , dword ptr[one.RMap]
shr ecx , 27 ; 0000001bH
;and ecx , 15 ; 0000000fH
; 把one.RMap中的要移動的數碼取出,並把該位清零----“空格”~
imul ecx , 3
mov ebx , 7
shl ebx , cl
mov eax , ebx
and ebx , dword ptr[one.RMap] ; 把數碼取出放在 ebx 中
shr ebx , cl
not eax
and dword ptr[one.RMap], eax ; 把該位清零----“空格”操作
; 把now.RMap.empty 空格的位置取出(即移動前,空格所在位置)
mov ecx , dword ptr[now.RMap]
shr ecx , 27 ; 0000001bH
;and ecx , 15 ; 0000000fH
; 把取出的數碼移到空格位置上去
imul ecx , 3
shl ebx , cl
or dword ptr[one.RMap] , ebx
}
flage = InsetHashTable( one.RMap , now.index );
if( flage >= 0 )
...{
one.gx = now.gx +1 ;
Evaluate(one);
one.parent = now.index ;
one.index = flage ;
Queue.push(one);
}
}
}
}
}
void input(Nodes& begin)
...{
int i ,j ;
int sum =0 , k ;
Map temp ;
printf("請輸入相應八數碼的位置: ");
for(i =0 ;i < 9 ; i ++ )...{
scanf("%I8d",&temp.Board[i]);
if(temp.Board[i] == 0 )
...{
k = i ;
continue;
}
for(j =0 ; j< i ; j ++ )
if(temp.Board[j] > temp.Board[i]) sum ++ ;
}
temp.empty = k ;
ReduceTheMap(temp,begin.RMap);
if(sum%2) memcpy(Target,DlTarget[1],8);
else memcpy(Target,DlTarget[0],8);
Evaluate(begin);
begin.index = InsetHashTable(begin.RMap);
return ;
}
void output()...{
if(Stack.length <= 0 ) printf("已經是目標狀態了,你這不是自找麻煩嘛! ");
else
...{
Map temp ;
printf("搞定! 供需 %d 步 , 步驟如下: ",Stack.length );
for(int i =Stack.length ; i >= 0 ; i -- )
...{
UnreduceMap( temp , Stack.pop());
temp.print();
getchar();
if(i) printf(" ----> ");
}
}
printf(" ");
return ;
}
int main()
...{
Nodes begin ;
input(begin);
long time = GetTickCount();
search(begin);
printf("計算耗時:%dMS ",GetTickCount()-time);
output();
return 0 ;
}
運行效果爲:
爲了便於複製代碼(因此便有下面的了):
#include <stdio.h>
#include <memory.h>
#include <windows.h>
#define HashTableSize 260441 // 562147 460387 400249 360323 260441
#define HeapSize 5000
#define MaxSteps 100
/*** 經過從 1 2 3 4 5 6 7 8 0 到 0 8 7 6 5 4 3 2 1 枚舉測試,
各個素數(HashTableSize) 的 hash 查詢次數和表使用率如下:
素數 平均查詢次數 使用率
562147 1.22 32.3%
460387 1.28 39.4%
400249 1.36 45.3%
360323 1.41 50.4%
260441 1.75 70.0%
*/
/***
這個棋盤採用4個字節表示。
其中 空格, 以及對應的 1~ 8 的數字, 用三個位表示, 然後 用四個位表示 空格的位置
(這共花了 3 * 9 + 4 = 31 個位 )。
注意棋盤是按 從上到下,從左到右, 依次標上編號:
--------------
| 00 | 01 | 02 |
--------------
| 03 | 04 | 05 |
--------------
| 06 | 07 | 08 |
--------------
棋盤表示法:
000 : 1 , 001 : 2 , 010 : 3
011 : 4 , 100 : 5 , 101 : 6
110 : 7 , 111 : 8 , 000 : 空格.
注意: 有的這裏 空格的位置 和 數碼 1 的編碼是一樣,這並不矛盾, 因爲實際上 空格編碼可以刪除,
因爲 後面要用 4 個位記錄空格位置。 那麼爲什麼還給 空格編碼呢? 這主要是對壓縮棋盤的上下左右
移動更加方便。
例如: 在 對下 棋盤:
6 8 3
0 5 2
4 7 1
那麼對應的Reduce_Map 編碼是: 101 111 010 000 100 001 011 110 000 0011 0
--- --- --- --- --- --- --- --- --- ---- ---
6 8 3 空格 5 2 4 7 1 3 標誌位
*/
/*** 棋盤數據結構 ****/
typedef struct reduce{
public:
unsigned a00: 3 , a01: 3 , a02: 3 ;
unsigned a03: 3 , a04: 3 , a05: 3 ;
unsigned a06: 3 , a07: 3 , a08: 3 ;
unsigned empty: 4 ; // 記錄 空格的位置.
unsigned used: 1 ; // 在 HashTable 元素中該位用來表示,是否已經佔了。
reduce():used(0){}
bool operator == (const reduce& a);
}Reduce_Map ;
/**棋盤的表示**/
typedef struct {
public:
unsigned __int8 Board[9];
unsigned __int8 empty ;
void print()
{
for(int i =0 ; i < 9 ; i ++ )
{
if(i%3 == 0 ) printf("/n");
printf("%5d",Board[i]);
}
}
}Map ;
/*****搜索的節點的表示******/
struct Nodes{
public:
Reduce_Map RMap ;
unsigned __int8 gx ;
unsigned __int8 fx ;
// unsigned short hx ; // hx = fx - gx ;
unsigned int parent ; // 父節點, 在hash表中的位置
unsigned int index ; // 該節點在hashtable中的位置
Nodes():gx(0),fx(0){}
void Evaluate(){}
};
/***棧:用來記錄路徑**/
struct stacks{
public:
__int8 length ;
Reduce_Map path[MaxSteps];
stacks():length(-1){}
void push(Reduce_Map& temp){ path[++length] = temp; }
Reduce_Map pop(){ return path[length--] ; }
}Stack;
/****hash表****/
struct hashtable{
Reduce_Map status ;
int PreIndex ; // 用來記錄 該節點的父節點在HashTable中對應的位置。
}HashTable[HashTableSize];
/****優先隊列******/
struct PriorityQueue
{
public:
Nodes Heap[HeapSize]; // 堆數組
int bear ; // 堆長度
PriorityQueue():bear(-1){}
Nodes pop();
void push(Nodes);
void print();
bool empty(){ return (bear== -1);}
}Queue;
void inline swap(Nodes& , Nodes&);
bool inline compare(const Nodes& , const Nodes&);
/*** 重載 == 運算符*****/
bool reduce::operator ==(const reduce& a)
{
static Reduce_Map temp ;
temp = a ;
temp.used = this->used ;
if( memcmp( this , &temp , 4 ) == 0 ) return true ;
return false ;
}
void PriorityQueue::push(Nodes temp)
{
Heap[++bear] = temp ;
int k = bear, p ;
while(k)
{
p = (k - 1 )>>1;
if( compare( Heap[k],Heap[p]) ) return ;
swap(Heap[k],Heap[p]);
k = p ;
}
return ;
}
Nodes PriorityQueue::pop()
{
int flage , k = 0 , p ;
swap(Heap[0],Heap[bear--]);
while( ( p = ( k << 1 ) ) < bear )
{
flage = 1;
if( ( (p + 1) < bear ) && compare( Heap[ p + 1 ] , Heap[ p + 2 ] ) ) flage ++ ;
if(compare( Heap[ p + flage ] , Heap[k] ) ) break ;
swap(Heap[ p + flage] , Heap[k]);
k = p + flage ;
}
return Heap[bear+1];
}
void PriorityQueue::print()
{
for(int i =0 ; i <= bear; i ++ )
printf("/tfx:%d hx:%d/t/n",Heap[i].fx , Heap[i].fx-Heap[i].gx);
printf("/n");
getchar();
}
/**方格中不同位置之間的距離**/
static unsigned __int8 Steps[9][9]={
{ 0 , 1 , 2 , 1 , 2 , 3 , 2 , 3 , 4 } ,
{ 1 , 0 , 1 , 2 , 1 , 2 , 3 , 2 , 3 } ,
{ 2 , 1 , 0 , 3 , 2 , 1 , 4 , 3 , 2 } ,
{ 1 , 2 , 3 , 0 , 1 , 2 , 1 , 2 , 3 } ,
{ 2 , 1 , 2 , 1 , 0 , 1 , 2 , 1 , 2 } ,
{ 3 , 2 , 1 , 2 , 1 , 0 , 3 , 2 , 1 } ,
{ 2 , 3 , 4 , 1 , 2 , 3 , 0 , 1 , 2 } ,
{ 3 , 2 , 3 , 2 , 1 , 2 , 1 , 0 , 1 } ,
{ 4 , 3 , 2 , 3 , 2 , 1 , 2 , 1 , 0 }
};
/**兩中目標狀態***/
static unsigned __int8 DlTarget[2][8]={
{ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 },
{ 0 , 1 , 2 , 5 , 8 , 7 , 6 , 3 }
};
static __int8 Derection[4] = { 1 , -1 , 3 , -3 } ;
//static char DeToChar[4] = {'r', 'l','d', 'u'} ;
/******目標狀態********/
static unsigned __int8 Target[8] ;
bool inline compare(const Nodes& Nodes1, const Nodes &Nodes2)
{
if(Nodes1.fx > Nodes2.fx) return true ;
if(Nodes1.fx < Nodes2.fx) return false;
return(Nodes1.gx < Nodes2.gx);
}
void inline swap(Nodes& a , Nodes&b)
{
Nodes c = b ;
b = a ;
a = c ;
}
/*** 棋盤的壓縮**/
inline void ReduceTheMap(Map& IMap , Reduce_Map& RMap )
{
IMap.Board[IMap.empty] ++ ;
RMap.a00 = IMap.Board[0] - 1 , RMap.a01 = IMap.Board[1] - 1 , RMap.a02 = IMap.Board[2] - 1;
RMap.a03 = IMap.Board[3] - 1 , RMap.a04 = IMap.Board[4] - 1 , RMap.a05 = IMap.Board[5] - 1;
RMap.a06 = IMap.Board[6] - 1 , RMap.a07 = IMap.Board[7] - 1 , RMap.a08 = IMap.Board[8] - 1;
RMap.empty = IMap.empty ;
IMap.Board[IMap.empty] -- ;
return ;
}
/*** 棋盤的解壓**/
inline void UnreduceMap(Map& IMap , Reduce_Map& RMap)
{
IMap.Board[0] = RMap.a00 + 1 , IMap.Board[1] = RMap.a01 + 1 , IMap.Board[2] = RMap.a02 + 1 ;
IMap.Board[3] = RMap.a03 + 1 , IMap.Board[4] = RMap.a04 + 1 , IMap.Board[5] = RMap.a05 + 1 ;
IMap.Board[6] = RMap.a06 + 1 , IMap.Board[7] = RMap.a07 + 1 , IMap.Board[8] = RMap.a08 + 1 ;
IMap.empty = RMap.empty ;
IMap.Board[IMap.empty] -- ;
return ;
}
/*** 判斷是否查找過了(使用雙散列函數探測法),
函數返回該節點在hashtable中的位置,
如果返回值爲:-1 表示已經存在
*/
int InsetHashTable( Reduce_Map RMap , int PreIndex = -1 )
{
unsigned int Code;
__asm // 彙編實現同字節不同類型值的賦值: Code = RMap
{
mov eax,dword ptr[RMap]
mov dword ptr[Code] ,eax
}
Code %= HashTableSize;
if(HashTable[Code].status.used == 0 ) // 如果used 爲 0 ,表示 該處未被佔用
{
HashTable[Code].status = RMap ;
HashTable[Code].status.used = 1 ;
HashTable[Code].PreIndex = PreIndex ; // 記錄父節點在hashtable中的位置,便於回溯找路徑
return Code ;
}
if( HashTable[Code].status == RMap ) return -1 ;
unsigned int temp = Code | RMap.empty; // 經過測試,這樣簡單操作後,使得二次探測碰撞減少了些~~
while(HashTable[Code].status.used == 1 ){
Code += temp ;
if(Code >= HashTableSize) Code -= HashTableSize ;
if( HashTable[Code].status == RMap ) return -1 ;
}
HashTable[Code].status = RMap ;
HashTable[Code].status.used = 1 ;
HashTable[Code].PreIndex = PreIndex ;
return Code ;
}
/***對 hx 的估價(使用的是: 每個數碼到目標位置的距離 之和 ) ***/
inline void Evaluate(Nodes& one)
{
one.fx = - Steps[ one.RMap.empty ][ Target[ 0 ] ] ;
one.fx += Steps[ 0 ][ Target[ one.RMap.a00 ] ] + Steps[ 1 ][ Target[ one.RMap.a01 ] ] +
Steps[ 2 ][ Target[ one.RMap.a02 ] ] + Steps[ 3 ][ Target[ one.RMap.a03 ] ] +
Steps[ 4 ][ Target[ one.RMap.a04 ] ] + Steps[ 5 ][ Target[ one.RMap.a05 ] ] +
Steps[ 6 ][ Target[ one.RMap.a06 ] ] + Steps[ 7 ][ Target[ one.RMap.a07 ] ] +
Steps[ 8 ][ Target[ one.RMap.a08 ] ] ;
one.fx += one.gx ;
}
/****回溯找出路徑***/
void FindFinalPath(unsigned int& ObjIndex )
{
int temp = ObjIndex ;
while(temp != -1 )
{
Stack.push(HashTable[temp].status);
temp = HashTable[temp].PreIndex;
}
return ;
}
void search(Nodes begin ){
Nodes one , now ;
int temp , flage ;
Queue.push(begin);
while( !Queue.empty() ){
now = Queue.pop();
if(now.gx == now.fx )
{
FindFinalPath(now.index);
return ;
}
for(int k =0 ; k < 4; k ++ )
{
temp = now.RMap.empty + Derection[k] ;
if(temp >=0 && temp< 9 && Steps[temp][now.RMap.empty] == 1 )
{
one.RMap = now.RMap ;
one.RMap.empty = temp;
__asm // 由於這裏RMap 被定義爲struct 類型, 因此移動很不方便,所以只好採用彙編了
{
; 把one.RMap.empty 空格的位置取出(即移動後 空格所在位置)
mov ecx , dword ptr[one.RMap]
shr ecx , 27 ; 0000001bH
;and ecx , 15 ; 0000000fH
; 把one.RMap中的要移動的數碼取出,並把該位清零----“空格”~
imul ecx , 3
mov ebx , 7
shl ebx , cl
mov eax , ebx
and ebx , dword ptr[one.RMap] ; 把數碼取出放在 ebx 中
shr ebx , cl
not eax
and dword ptr[one.RMap], eax ; 把該位清零----“空格”操作
; 把now.RMap.empty 空格的位置取出(即移動前,空格所在位置)
mov ecx , dword ptr[now.RMap]
shr ecx , 27 ; 0000001bH
;and ecx , 15 ; 0000000fH
; 把取出的數碼移到空格位置上去
imul ecx , 3
shl ebx , cl
or dword ptr[one.RMap] , ebx
}
flage = InsetHashTable( one.RMap , now.index );
if( flage >= 0 )
{
one.gx = now.gx +1 ;
Evaluate(one);
one.parent = now.index ;
one.index = flage ;
Queue.push(one);
}
}
}
}
}
void input(Nodes& begin)
{
int i ,j ;
int sum =0 , k ;
Map temp ;
printf("請輸入相應八數碼的位置:/n");
for(i =0 ;i < 9 ; i ++ ){
scanf("%I8d",&temp.Board[i]);
if(temp.Board[i] == 0 )
{
k = i ;
continue;
}
for(j =0 ; j< i ; j ++ )
if(temp.Board[j] > temp.Board[i]) sum ++ ;
}
temp.empty = k ;
ReduceTheMap(temp,begin.RMap);
if(sum%2) memcpy(Target,DlTarget[1],8);
else memcpy(Target,DlTarget[0],8);
Evaluate(begin);
begin.index = InsetHashTable(begin.RMap);
return ;
}
void output(){
if(Stack.length <= 0 ) printf("已經是目標狀態了,你這不是自找麻煩嘛!/n");
else
{
Map temp ;
printf("搞定!/t 供需 %d 步 , 步驟如下:/n",Stack.length );
for(int i =Stack.length ; i >= 0 ; i -- )
{
UnreduceMap( temp , Stack.pop());
temp.print();
getchar();
if(i) printf("/n/n---->/n");
}
}
printf("/n");
return ;
}
int main()
{
Nodes begin ;
input(begin);
long time = GetTickCount();
search(begin);
printf("計算耗時:%dMS/n",GetTickCount()-time);
output();
return 0 ;
}