拼图游戏(搜索算法)

【问题描述】
任意选择一张图片,将其切分成MxN个小块,去掉其中任意一块,然后打乱顺序。游戏规则是:经过若干步移动从而复原原始图片中小块的顺序,每次移动可以将与空格相邻的小块移动到空格处。
例如,选择图1所示的图片;将其切分为3x3个小块,去掉最后一块,形成图2所示的样子;随机打乱顺序后,形成图3的样子;将图1中9个小块按先行后列的顺序编号为0~8,8号小块被去掉,用-1表示空格,则图3就可对应为图4的矩阵。


图3的状态有两种合法的移动方式,分别如图5和图6所示。其中,将图4中空格上方的小块下移形成了图5,将图4中空格左侧的小块右移形成了图6。游戏时,需要通过若干步合法的移动,使得状态变为图7所示。

 

请给出使用优先队列搜索算法求解拼图游戏的【问题分析】和【算法伪代码】。

【问题分析】

这是一个八数码问题,在一个3*3的棋盘上,随机放置0-8的数字,去掉一个数字,出现空位,用-1来填补,数字可以移动到空位,经过若干次移动后,可以实现指定目标。

可以采用广度优先搜索算法遍历实现功能。

先构造一个优先队列,然后从空白格周围开始搜索,从上下左右四个方向找到可交换的位置,进行交换,然后把交换之后的状态放入优先队列中,从队列中取出队头元素,得到新的状态,将该状态与目标状态进行比较,若一样,则结束并返回此时交换次数,若不同,重复以上步骤,继续进行搜索。将交换后满足要求的状态入队,并标记访问,需要展开判重。

【算法伪代码】

//展开判重

Cantor(int str[], int n)

       sum = 0;

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

       {

              int cnt = 0;

              for (int j = i + 1; j < n; j++)

                     if (str[i] > str[j])

                            cnt++;

              sum += cnt * factory[n - i - 1];

       }

return sum;


//广度优先搜索算法

int bfs()

       Node head;

       memcpy(head.state, startstate, sizeof(startstate));

       head.step = 0;

       q.push(head);

       temp = 0;

       while (!q.empty())

       {

              temp++;

              head = q.top();

              q.pop();

              if (memcmp(head.state, goalstate, sizeof(goalstate)) == 0)

                     return head.step;

              if (temp >= 1000)

                     return -1;

              int k;

              for (k = 0; k < n * m; k++)

                     if (head.state[k] == -1)

                            break;

              int x = k % m;

              int y = k / m;

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

              {

                     int newx = x + xx[i];

                     int newy = y + yy[i];

                     int newpos = newx + m * newy;

                     if (newx >= 0 && newx < n && newy >= 0 && newy < m)

                            Node newnode;

                            memcpy(&newnode, &head, sizeof(Node));

                            Swap(newnode.state[k], newnode.state[newpos]);

                            newnode.step++;

                            newcan = Cantor(newnode.state, n * m);

                            if (!vis[newcan])  q.push(newnode);vis[newcan] = true;

                           

              }

       }

return -1;

【代码实现】

#include <bits/stdc++.h>
using namespace std;

const int n = 3;
const int m = 3;
const int len = 1000000;

int xx[4] = { -1,0,1,0 };
int yy[4] = { 0,-1,0,1 };
bool vis[len];
int startstate[n * m];
int goalstate[n * m];
long factory[n * m+1];

struct Node
{
    int state[9];
    int step;
};

int f(int k)
{
    int sum = 1;
    for (int i = 1; i <= k; i++)
        sum = sum * i;
    return sum;
}

int difnum(Node a)
{
    int num = 0;
    for (int i = 0; i < n * m; i++)
        if (a.state[i] != goalstate[i])
            num++;
    return num;
}

struct cmp
{
    bool operator()(Node& a, Node& b)
    {
        return a.step + difnum(a) > b.step + difnum(b);
    }
};
//优先队列
priority_queue<Node, vector<Node>, cmp> q;

//展开判重
int Cantor(int str[], int n)
{
    int sum = 0;
    for (int i = 0; i < n; i++)
    {
        int cnt = 0;
        for (int j = i + 1; j < n; j++)
            if (str[i] > str[j])
                cnt++;
        sum += cnt * factory[n - i - 1];
    }
    return sum;
}
//数据初始化,输入数据
void Init()
{
    int posn, posm;
    cin >> posn >> posm;
    for (int i = 0; i < n * m; i++)
        cin >> startstate[i];
    for (int i = 0; i < n * m; i++)
        goalstate[i] = i;
    goalstate[posn * m + posm] = -1;

    factory[1] = 1;
    for (int i = 1; i <= 9; i++)
    {
        factory[i] = f(i);
    }
}

void Swap(int &a, int &b)
{
    int c;
    for (int i = 0; i < n*m ; i++)
    {
        c = a;
        a = b;
        b = c;
    }
}
//广度遍历
int bfs()
{
    Node head;
    memcpy(head.state, startstate, sizeof(startstate));
    head.step = 0;
    q.push(head);
    int temp = 0;
    while (!q.empty())
    {
        temp++;
        head = q.top();
        q.pop();
        if (memcmp(head.state, goalstate, sizeof(goalstate)) == 0)
            return head.step;
        if (temp >= 1000)
            return -1;
        int k;
        for (k = 0; k < n * m; k++)
            if (head.state[k] == -1)
                break;
        int x = k % m;
        int y = k / m;
        for (int i = 0; i < 4; i++)
        {
            int newx = x + xx[i];
            int newy = y + yy[i];
            int newpos = newx + m * newy;
            if (newx >= 0 && newx < n && newy >= 0 && newy < m)
            {
                Node newnode;
                memcpy(&newnode, &head, sizeof(Node));
                Swap(newnode.state[k], newnode.state[newpos]);
                newnode.step++;
                int newcan = Cantor(newnode.state, n * m);
                if (!vis[newcan])
                {
                    q.push(newnode);
                    vis[newcan] = true;
                }
            }
        }
    }
    return -1;
}

int main()
{
    Init();
    cout << bfs() << endl;
    return 0;
}

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值