滑塊拼圖(加強版的8數碼)的規劃處理

 

 

最近回顧了下BFS,DFS,以及八數碼問題

週末的時候在家突然看到了角落裏的滑塊拼圖,放了很久了。

玩滑塊拼圖,沒有找到什麼規律的話太難下手了。

這時,考慮用程序來處理下。

 

 

3*4 + 1的拼圖,是8數碼的升級版,8數碼問題的資料還比較多,是一個非常經典的問題

 

https://blog.csdn.net/u012283461/article/details/79078653

https://www.jianshu.com/p/9c39e80cc877

 

常規的處理需要保存所有可能的狀態,估算下狀態總數爲

13! = 6 227 020 800

數據量非常大,大概是6G大小

 

初始形態

 

 

 

 

 

模型圖如下

 

 

 

這裏,考慮分塊處理,先拼好部分位置,如最下面的一行,

 

 

再處理剩餘的部分,數據量下降後就可以類似8數碼的解決方案去處理3*3 + 1的拼圖了

 

 

這裏探討一下使用bfs方法找到最下面一行的處理方案

 

現在只關心4個小圖片的存放位置,

//通過15*15*15*15的存儲空間,可以保存4個塊的所有排列組合方案(使用15*15*15*15還是有冗餘空間的)

//pixrecords[15][15][15][15] = {0};

//record the 4 pix

//pixrecords[12][14][7][6]表示數字10在12位置,數字11在14位置,數字12在7位置,空白塊在6位置

 

其他的處理就是常規的廣度優先搜索了,使用一個隊列去實現。

 

 

VC6中編譯通過的code

#include <cmath>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <iostream>

#include <algorithm>

 

#include <string.h>

#include <queue>

 

using namespace std;

 

int width = 3;

int height = 5;

 

struct PNode{

    char state[15];

    char steps[32];

    char pos[4];

// int pred;

    PNode()

    {

    }

};

 

//record the 0,1,2,3 pix

//pixrecords[12][14][7][6]表示數字1在12位置,數字2在14位置,數字3在7位置,空白塊在6位置

//通過15*15*15*15的存儲空間,可以保存4個塊的所有排列組合方案

char pixrecords[15][15][15][15] = {0};

 

//

//right left, up down

int directions[8] = {0, 1, 0, -1, -1, 0, 1, 0};

 

 

 

bool isMoveable(int x, int y, int d)

{

//d 1 2 3 4

    x += directions[2*(d-1)];

    y += directions[2*(d-1) + 1];

 

    if (y >= 0 && y <= 2 && x >=1 && x <=4)

    {

        return true;

    }

 

    if (y == 2 && x == 0)

    {

        return true;

    }

 

    return false;

 

}

 

int move(char* data, char* positon, int d)

{

    int x = positon[3] / 3;

    int y = positon[3] % 3;

    int x1 = x + directions[2*(d-1)];

    int y1 = y + directions[2*(d-1) + 1];

 

//    printf("The begin positions = %d %d %d %d, d=%d, x=%d,y=%d, x1=%d, y1=%d\n",

//        positon[0],positon[1],positon[2],positon[3],d,x,y,x1,y1);

 

    for (int i = 0; i < 3; i++)

    {

        if (positon[i] == width*x1 + y1)

        {

            positon[i] = width*x + y;

        }

    }

    positon[3] = width*x1 + y1;

    int p1 = positon[0];

    int p2 = positon[1];

    int p3 = positon[2];

    int p4 = positon[3];

 

 

    if (pixrecords[p1][p2][p3][p4] == 1)

    {

        printf("positions = %d %d %d %d\n", p1,p2,p3,p4);

        return 0;

    }

 

    pixrecords[p1][p2][p3][p4] = 1;

    printf("make 1, positions = %d %d %d %d\n", p1,p2,p3,p4);

 

    int tmp = data[width*x + y];

    data[width*x + y] = data[width*x1 + y1];

    data[width*x1 + y1] = tmp;

 

    return 1;

}

 

bool isOk(char* data)

{

    if (data[12] == 10 && data[13] == 11 && data[14] == 12)

    {

        return true;

    }

    return false;

}

 

int getIndex(char* data, char value)

{

    for (int i = 0; i < 15; i++)

    {

        if (data[i] == value)

        {

            return i;

        }

    }

 

    return 0;

}

 

int main()

{

//這裏我們只關心4個小塊,他們的值分別設置爲10,11,12,13(空白塊)

     char beginData[15] = {

        0,  0, 9,

        9,  9, 9,

        13, 9, 9,

        9, 10, 9,

        12,11, 9};

 

    char pixpositon[4];

    //for example

//    char pixpositon[4] = {5, 11, 7, 4};

//    pixrecords[5][11][7][4] = 1;

 

    pixpositon[0] = getIndex(beginData, 10);

    pixpositon[1] = getIndex(beginData, 11);

    pixpositon[2] = getIndex(beginData, 12);

    pixpositon[3] = getIndex(beginData, 13);

 

    pixrecords[pixpositon[0]][pixpositon[1]][pixpositon[2]][pixpositon[3]] = 1;

 

    PNode start;

    memcpy(start.state, beginData, 15);

    memset(start.steps, 0, 32);

    memcpy(start.pos, pixpositon, 4);

 

    queue<PNode> plist;

    plist.push(start);

 

    int pcount = 0;

    while (!plist.empty())

    {

        pcount++;

        if (pcount % 100 == 0)

        {

            cout << "count = " << pcount << ", list len = " << plist.size() << endl;

        }

        PNode cur = plist.front();

        plist.pop();

 

        if (isOk(cur.state))

        {

            //cout << "the steps is; " << cur.steps << endl;

            for (int i = 0; i < strlen(cur.steps); i++)

            {

                printf(" %d,", cur.steps[i]);

            }

            cout << endl;

            //right left, up down

            for (i = 0; i < strlen(cur.steps); i++)

            {

                if (cur.steps[i] == 1)  printf(" right,");

                if (cur.steps[i] == 2)  printf(" left,");

                if (cur.steps[i] == 3)  printf(" up,");

                if (cur.steps[i] == 4)  printf(" down,");                    

            }

            cout << endl;

 

            break;

        }

 

        for (int i = 1; i <= 4; i++)

        {

            if (isMoveable(cur.pos[3]/3, cur.pos[3]%3, i))

            {

        //        cout << "in moveable " << endl;

                PNode node;

                memcpy(&node, &cur, sizeof(PNode));

                if (move(node.state, node.pos, i) == 1)

                {                    

                    int len = strlen(node.steps);

                    node.steps[len] = i;

 

                    plist.push(node);

                //    cout << "push " << endl;

                }

 

            }

        }

 

    }

 

cout << "end, count = "<< pcount << endl;

return 0;

}

 

執行結果

4, 1, 4, 2, 3, 3, 1, 1, 4, 4, 2, 3,

down, right, down, left, up, up, right, right, down, down, left, up,

 

 

可以繼續使用這個方法來排3個小圖片

 

up, left, up, right,

 

 

 

這樣問題的規模越來越小了,再選擇3個進行處理,下圖紅色部分

 

 

4, 4, 1, 3,

down, down, right, up,

 

 

 

就差不多還原好了,只差最後一擊了

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章