九宮格拼圖拼到如圖就不會了求大神解答

2021-03-03 22:16:23 字數 6060 閱讀 7649

1樓:筱弦

拼圖?是指滑塊之類的東西嗎?

很遺憾,這不可能實現

望採納,謝謝o(∩_∩)o

2樓:匿名使用者

你確定有解嗎?我用廣度優先搜尋遍歷了一遍沒找到解

九宮格拼圖·求此問題解法~~思路~**都可~~就是關於其還原演算法的·急~**等~多謝哈

3樓:匿名使用者

在一個3×3的九宮中有1-8這8個數及一個空格隨機的擺放在其中的格子裡,如圖1-1所示。現在要求實現這個問題:將其調整為如圖1-1右圖所示的形式。

調整的規則是:每次只能將與空格(上、下、或左、右)相鄰的一個數字平移到空格中。試程式設計實現這一問題的求解。

(圖1-1)

二、題目分析:

這是人工智慧中的經典難題之一,問題是在3×3方格棋盤中,放8格數,剩下的沒有放到的為空,每次移動只能是和相鄰的空格交換數。程式自動產生問題的初始狀態,通過一系列交換動作將其轉換成目標排列(如下圖1-2到圖1-3的轉換)。

(圖1-2) (圖1-3)

該問題中,程式產生的隨機排列轉換成目標共有兩種可能,而且這兩種不可能同時成立,也就是奇數排列和偶數排列。可以把一個隨機排列的陣列從左到右從上到下用一個一維陣列表示,如上圖1-2我們就可以表示成{8,7,1,5,2,6,3,4,0}其中0代表空格。

在這個陣列中我們首先計算它能夠重排列出來的結果,公式就是:

∑(f(x))=y,其中f(x)

是一個數前面比這個數小的數的個數,y為奇數和偶數時各有一種解法。(八數碼問題是否有解的判定 )

上面的陣列可以解出它的結果。

f(8)=0;

f(7)=0;

f(1)=0;

f(5)=1;

f(2)=1;

f(6)=3;

f(3)=2;

f(4)=3;

y=0+0+0+1+1+3+2+3=10

y=10是偶數,所以其重排列就是如圖1-3的結果,如果加起來的結果是奇數重排的結果就是如圖1-1最右邊的排法。

三、演算法分析

求解方法就是交換空格(0)位置,直至到達目標位置為止。圖形表示就是:

(圖3-1)

要想得到最優的就需要使用廣度優先搜尋,九宮的所以排列有9!種,也就是362880種排法,資料量是非常大的,使用廣度搜尋,需要記住每一個結點的排列形式,要是用陣列記錄的話會佔用很多的記憶體,可以把資料進行適當的壓縮。使用dword形式儲存,壓縮形式是每個數字用3位表示,這樣就是3×9=27個位元組,由於8的二進位制表示形式1000,不能用3位表示,使用了一個小技巧就是將8表示為000,然後用多出來的5個字表示8所在的位置,就可以用dword表示了。

用移位和或操作將資料逐個移入,比乘法速度要快點。定義了幾個結果來儲存遍歷到了結果和搜尋完成後儲存最優路徑。

類結構如下:

class **inegird

;struct scanbuf

;struct pathlist

;private:

placelist *m_pplacelist;

scanbuf *m_pscanbuf;

rect m_rresetbutton;

rect m_rautobutton;

public:

int m_ipathsize;

clock_t m_itime;

uint m_istepcount;

unsigned char m_itargetchess[9];

unsigned char m_ichess[9];

hwnd m_hclientwin;

pathlist *m_ppathlist;

bool m_bautorun;

private:

inline bool addtree(dword place , placelist*& parent);

void freetree(placelist*& parent);

inline void arraytodword(unsigned char *array , dword & data);

inline void dwordtoarray(dword data , unsigned char *array);

inline bool movechess(unsigned char *array , int way);

bool estimateuncoil(unsigned char *array);

void getpath(uint depth);

public:

void movechess(int way);

bool ***putefeel();

void activeshaw(hwnd hview);

void drawgird(hdc hdc , rect clientrect);

void drawchess(hdc hdc , rect clientrect);

void reset();

void onbutton(point pnt , hwnd hview);

public:

**inegird();

~**inegird();

};計算隨機隨機陣列使用了vector模板用random_shuffle(,)函式來打亂陣列資料,並計算目標結果是什麼。**:

void **inegird::reset()

if (!estimateuncoil(m_ichess))

;memcpy(m_itargetchess , array , 9);

}else

;memcpy(m_itargetchess , array , 9);

}m_istepcount = 0;

}資料壓縮函式實現:

inline void **inegird::arraytodword(unsigned char *array , dword& data)

}array[night] = 0;

data = 0;

data = (dword)((dword)array[0] << 29 | (dword)array[1] << 26 |

(dword)array[2] << 23 | (dword)array[3] << 20 |

(dword)array[4] << 17 | (dword)array[5] << 14 |

(dword)array[6] << 11 | (dword)array[7] << 8 |

(dword)array[8] << 5 | night);

array[night] = 8;

}解壓縮時跟壓縮正好相反,解壓**:

inline void **inegird::dwordtoarray(dword data , unsigned char *array)

chtem = (unsigned char)(data & 0x0000001f);

array[chtem] = 8;

}由於可擴充套件的資料量非常的大,加上在儲存的時候使用的是dword型別,將每一步資料都記錄在一個排序二叉樹中,按從小到大從左到有的排列,搜尋的時候跟每次搜尋將近萬次的形式比較快幾乎是n次方倍,把幾個在迴圈中用到的函式宣告為行內函數,並在插入的時候同時搜尋插入的資料會不會在樹中有重複來加快總體速度。二叉樹插入**:

inline bool **inegird::addtree(dword place , placelist*& parent)

if (parent->place == place)

return false;

if (parent->place > place)

return addtree(place , parent->left);

}計算結果是奇數排列還是偶數排列的**:

bool **inegird::estimateuncoil(unsigned char *array)}}

if (sun % 2 == 0)

return true;

else

return false;

}移動到空格位的**比較簡單,只要計算是否會移動到框外面就可以了,並在移動的時候順便計算一下是不是已經是目標結果,這是用來給使用者手工移動是給與提示用的,**:

inline bool **inegird::movechess(unsigned char *array , int way)

point pnt;

pnt.x = zero % 3;

pnt.y = int(zero / 3);

switch(way)

break;

case 1 : //down

if (pnt.y - 1 > -1)

break;

case 2 : //left

if (pnt.x + 1 < 3)

break;

case 3 : //right

if (pnt.x - 1 > -1)

break;

}if (moveok && !m_bautorun)

}return moveok;

}在進行廣度搜尋時候,將父結點所在的陣列索引記錄在子結點中了,所以得到目標排列的時候,只要從子結點逆向搜尋就可以得到最優搜尋路徑了。用變數m_ipathsize來記錄總步數,具體函式**:

void **inegird::getpath(uint depth)

m_ppathlist = new pathlist[maxpos];

parentid = m_pscanbuf[depth].scanid;

dwordtoarray(m_pscanbuf[depth].place , m_ppathlist[++now].path);

while(parentid != -1)

dwordtoarray(m_pscanbuf[parentid].place , m_ppathlist[++now].path);

parentid = m_pscanbuf[parentid].scanid;

}m_ipathsize = now;

}動態排列的演示函式最簡單了,為了讓主窗體有及時重新整理的機會,啟動了一個執行緒在需要主窗體重新整理的時候,用slee(uint)函式來暫停一下執行緒就可以了。**:

unsigned __stdcall movechessthread(lpvoid pparam)

char msg[100];

sprintf(msg , "^_^ ! 搞定了!\r\n計算步驟用時%d毫秒" , pgird->m_itime);

messagebox(null , msg , "~_~" , 0);

pgird->m_bautorun = false;

return 0l;

}最後介紹一下搜尋函式的原理,首先得到源陣列,將其轉換成dword型,與目標比較,如果相同完成,不同就交換一下資料和空格位置,加入二叉樹,搜尋下一個結果,直到沒有步可走了,在搜尋剛剛搜尋到的位置的子位置,這樣直到找到目標結果為止,函式:

bool **inegird::***putefeel()

if (m_pscanbuf != null)

m_pscanbuf = new scanbuf[maxsize];

addtree(fountain ,m_pplacelist);

m_pscanbuf[ 0 ].place = fountain;

m_pscanbuf[ 0 ].scanid = -1;

clock_t tim = clock();

while(parentid < maxsize && child < maxsize)

child ++;}}

} // for i

parentid++;

}m_itime = clock() - tim;

freetree(m_pplacelist);

delete m_pscanbuf;

m_pscanbuf = null;

return false;

}重要函式的介紹結束;下面是程式的執行結果和運算結果:

九宮格火鍋的由來,九宮格火鍋有什麼講究

一 為了方便拼桌 最早起源於重慶的江邊小販,五湖四海的江湖人士聚到一起,為了方便分清食物和結賬,所以就發明了九宮格。頗有幾分江湖氣息。二 為了方便找鍋裡的食物 吃火鍋經常遇到菜明明放到了鍋裡,卻怎麼找都找不到。有了九宮格,你的 搜尋 面積就只有九分之一。三 為了方便大家 劃分領土 吃火鍋最怕遇到的就...

九宮格老火鍋店怎麼樣,九宮格重慶老火鍋(九宮格火鍋)怎麼樣,好

不好吃,服務態度也不好,不給發票,而且很貴,九宮格也做得不地道,炒飯的蛋裡都是鹽 九宮格重慶老火鍋 九宮格火鍋 怎麼樣,好 九宮格是最早的重慶火鍋。據傳,祖先之所以將火鍋分為九格,最早的緣故是為了好算賬。當時在兩江會流的朝天門,小販們把一個鍋分成了九格以便不同的食客食用,顧客想吃哪格就哪格,吃完後按...

九宮格數字遊戲答案,九宮格填數字遊戲求答案

做了很久,終於把第一題做出來了。954 863 127 137 524 698 286 971 345 418 296 573 723 185 469 569 347 812 891 432 756 375 619 284 642 758 931 還有第二題 684 573 291 152 896 ...