推箱子问题

//参考:http://www.acmerblog.com/hdu-1254-推箱子-1618.html

#include <iostream>
#include <fstream>
#include <queue>
#include <cmath>
#include <cstdlib>
using namespace std;

class Node
{
public:
    int box_x;
    int box_y;
    int people_x;
    int people_y;
    int step;

    Node(){}

    //步数小的结点先出队列
    bool operator < (const Node &node) const
    {
        return step > node.step;
    }
};

const int MAX = 20;
priority_queue<Node> q;
int box_x, box_y;
int people_x, people_y;
int end_x, end_y;
char board[MAX][MAX];
int dx[] = {0, 0,  1, -1};
int dy[] = {1, -1, 0,  0};
int n, m;            //n * m矩形阵列
bool flag = false;   //是否找到解
bool flag1 = false;  //人是否可以到达可以推箱子的地方
int visit[MAX][MAX][MAX][MAX];  //visit[a][b][c][d]=1 表示(a, b)中的箱子被(c, d)中的人推过
int visit2[MAX][MAX];  
int best;            //最少推动步数

//深度搜索,人是否能到达推箱子的位置(to_x, to_y),到达才能推位置(box_x, box_y)上的箱子
bool dfs(int to_x, int to_y, int box_x, int box_y, int people_x, int people_y)
{
    visit2[people_x][people_y] = 1;
    if(to_x == people_x && to_y == people_y)
    {
        flag1 = true;
        return true;
    }
    if(!flag1)
    {
        for(int i=0; i<4; i++)
        {
            int xx = people_x + dx[i]; 
            int yy = people_y + dy[i];  
            if(xx<1 || yy<1 || xx>n || yy>m || (xx==box_x && yy==box_y) || board[xx][yy]=='S' || visit2[xx][yy])
                continue;
            dfs(to_x, to_y, box_x, box_y, xx, yy);
            if(flag1)
                return true;
        }
    }  
    return false;
}

void bfs()
{
    while(!q.empty())
    {
        Node cur = q.top(); 
        q.pop();
        if(cur.box_x == end_x && cur.box_y == end_y)
        {
            best  = cur.step;
            flag = true;
            break;
        }

        else
        for(int i=0; i<4; i++)
        {
            flag1 = false;
            memset(visit2, 0, sizeof(visit2));
            int x = cur.box_x + dx[i];
            int y = cur.box_y + dy[i];
            if(x<1 || y<1 || x>n || y>m || board[x][y]=='S')
                continue;
            Node next;
            next.box_x = x;
            next.box_y = y;
            next.people_x = cur.box_x;  
            next.people_y = cur.box_y;
            next.step = cur.step + 1;   
            if(i==0)  
                if(cur.box_y-1>0) //如果推箱子前的位置为空格,且可达,且没有在该位置推过箱子
                    if(board[cur.box_x][cur.box_y-1]!='S' && dfs(cur.box_x, cur.box_y-1, cur.box_x, cur.box_y, cur.people_x, cur.people_y) && !visit[x][y][cur.box_x][cur.box_y-1])
                    {
                        visit[x][y][cur.box_x][cur.box_y-1] = 1;
                        q.push(next);
                    }

            if(i==1)
                if(cur.box_y+1<=m)
                    if(board[cur.box_x][cur.box_y+1]!='S' && dfs(cur.box_x, cur.box_y+1, cur.box_x, cur.box_y, cur.people_x, cur.people_y) && !visit[x][y][cur.box_x][cur.box_y+1])
                    {
                        visit[x][y][cur.box_x][cur.box_y+1] = 1;
                        q.push(next);
                    }

            if(i==2)
                if(cur.box_x-1>0)
                    if(board[cur.box_x-1][cur.box_y]!='S' && dfs(cur.box_x-1, cur.box_y, cur.box_x, cur.box_y, cur.people_x, cur.people_y) && !visit[x][y][cur.box_x-1][cur.box_y])
                    {
                        visit[x][y][cur.box_x-1][cur.box_y] = 1;
                        q.push(next);
                    }

            if(i==3)
                if(cur.box_x+1<=n)
                    if(board[cur.box_x+1][cur.box_y]!='S' && dfs(cur.box_x+1, cur.box_y, cur.box_x, cur.box_y, cur.people_x, cur.people_y) && !visit[x][y][cur.box_x+1][cur.box_y])
                    {
                        visit[x][y][cur.box_x+1][cur.box_y] = 1;
                        q.push(next);
                    }
        }
    }
}

int main()
{
    ifstream fin("推箱子.txt");
    cout << "输入矩阵行数:";
    fin >> n;  cout << n << endl;
    cout << "输入矩阵列数:";
    fin >> m;  cout << m << endl;
    cout << "输入矩阵:\n";
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            fin >> board[i][j];
            cout << board[i][j];
            if(board[i][j] == 'P')
            {
                box_x = i;
                box_y = j;
            }
            if(board[i][j] == 'M')
            {
                people_x = i; 
                people_y = j;
            }
            if(board[i][j] == 'K')
            {
                end_x = i;
                end_y = j;
            }
        }
        cout << endl;
    }
    Node cur;
    cur.box_x = box_x;
    cur.box_y = box_y;
    cur.people_x = people_x;
    cur.people_y = people_y;
    cur.step = 0;
    q.push(cur);  
    memset(visit2, 0, sizeof(visit2));
    memset(visit, 0, sizeof(visit));

    bfs();
    if(flag)
        cout << "最少的推动次数为:" << best << endl;
    else
        cout << "No Solution!";

    cout << endl << endl;
    fin.close();
    return 0;
}

这里写图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
´问题描述: 码头仓库是划分为n×m个格子的矩形阵列。有公共边的格子是相邻格子。当前仓库中 有的格子是空闲的;有的格子则已经堆放了沉重的货物。由于堆放的货物很重,单凭仓库管 理员的力量是无法移动的。仓库管理员有一项任务,要将一个小箱子推到指定的格子上去。 管理员可以在仓库中移动,但不能跨过已经堆放了货物的格子。管理员站在与箱子相对的空 闲格子上时,可以做一次推动,把箱子推到另一相邻的空闲格子。推箱时只能向管理员的对 面方向推。由于要推动的箱子很重,仓库管理员想尽量减少推箱子的次数。 ´编程任务: 对于给定的仓库布局,以及仓库管理员在仓库中的位置和箱子的开始位置和目标位置, 设计一个解推箱子问题分支限界法, 计算出仓库管理员将箱子从开始位置推到目标位置所 需的最少推动次数。 ´数据输入: 由文件input.txt提供输入数据。输入文件第 1 行有 2个正整数 n和 m(1<=n,m<=100) , 表示仓库是n×m个格子的矩形阵列。接下来有 n行,每行有 m个字符,表示格子的状态。 S 表示格子上放了不可移动的沉重货物; w 表示格子空闲; M 表示仓库管理员的初始位置; P 表示箱子的初始位置; K 表示箱子的目标位置。 ´结果输出: 将计算出的最少推动次数输出到文件 output.txt。如果仓库管理员无法将箱子从开始位 置推到目标位置则输出“No solution!” 。 输入文件示例 输出文件示例 input.txt output.txt
推箱子问题,也称为 Sokoban,是一个经典的益智游戏。在这个游戏中,玩家需要将箱子推到指定的位置,通过推动和移动来达到目标。在计算机科学中,推箱子问题也被用来测试搜索算法和人工智能技术。 C++ 是一种流行的编程语言,可以用来实现推箱子问题的求解算法。其中常用的算法包括深度优先搜索、广度优先搜索、A* 算法等等。 以下是一个简单的 C++ 代码示例,展示了如何实现深度优先搜索算法来解决推箱子问题。请注意,此代码并不完整,仅供参考。 ``` #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N = 20; int n, m, sx, sy, tx, ty; char g[N][N]; bool st[N][N][N][N]; struct Node { int x, y, px, py; }; int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}; bool dfs(int x, int y, int px, int py) { if (g[x][y] == 'T') return true; if (st[x][y][px][py]) return false; st[x][y][px][py] = true; for (int i = 0; i < 4; i++) { int a = x + dx[i], b = y + dy[i]; if (g[a][b] == '#') continue; if (a == px && b == py) { int c = a + dx[i], d = b + dy[i]; if (g[c][d] == '#') continue; g[a][b] = '.'; g[c][d] = 'O'; if (dfs(a, b, c, d)) return true; g[a][b] = 'O'; g[c][d] = '.'; } else { if (dfs(a, b, x, y)) return true; } } return false; } int main() { while (cin >> n >> m) { memset(st, 0, sizeof st); memset(g, '#', sizeof g); for (int i = 1; i <= n; i++) { getchar(); for (int j = 1; j <= m; j++) { cin >> g[i][j]; if (g[i][j] == 'S') sx = i, sy = j; if (g[i][j] == 'T') tx = i, ty = j; } } bool success = dfs(sx, sy, -1, -1); if (success) cout << "YES" << endl; else cout << "NO" << endl; } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值