多米诺覆盖问题的回溯解法

题目:现有6*6大小的棋盘和18张多米诺骨牌,每张牌能覆盖2个棋格,求将多米诺骨牌完全覆盖棋盘的所有组合?

 

 

#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <sstream>

using namespace std;

const int MAX_LENGTH = 2 * 3;
set<string> result;

//=================
// 棋盘位置类
//=================
class Position
{
private:
    int x;
    int y;

public:
    Position() : x(-1), y(-1)
    {
    }

    Position(const Position& position) : x(position.getX()), y(position.getY())
    {
    }

    Position(int x, int y) : x(x), y(y)
    {
        if (x < 0 || x >= MAX_LENGTH)
        {
            x = -1;
        }
        if (y < 0 || y >= MAX_LENGTH)
        {
            y = -1;
        }
    }

    int getX() const
    {
        return x;
    }

    int getY() const
    {
        return y;
    }

    Position getRight()
    {
        return Position(x, y + 1);
    }

    Position getBottom()
    {
        return Position(x + 1, y);
    }

    bool valid() const
    {
        return x >= 0 && x < MAX_LENGTH && y >= 0 && y < MAX_LENGTH;
    }

    bool operator==(const Position& right) const
    {
        return x == right.getX() && y == right.getY();
    }
};

//=================
// 棋子类
//=================
class Chessman
{
private:
    pair<Position, Position> positions;

public:
    Chessman()
    {
    }
    
    Chessman(const pair<Position, Position>& positions) : positions(positions)
    {
    }

    pair<Position, Position> getPositions() const
    {
        return positions;
    }

    bool valid() const
    {
        if (!positions.first.valid() || !positions.second.valid())
        {
            return false;
        }

        if (positions.first == positions.second)
        {
            return false;
        }
        return true;
    }

    bool isXdirection() const
    {
        if (!valid())
        {
            return false;
        }
        return positions.first.getX() == positions.second.getX();
    }
};

//=================
// 棋盘类
//=================
class Chessboard
{
private:
    size_t board[MAX_LENGTH][MAX_LENGTH];
    stack<Chessman> chessmen;

public:
    Chessboard()
    {
        for (int i = 0; i < MAX_LENGTH; i++)
        {
            for (int j = 0; j < MAX_LENGTH; j++)
            {
                board[i][j] = 0;
            }
        }
    }

    bool hold(const Chessman& chessman)
    {
        pair<Position, Position> positions = chessman.getPositions();

        Position first = positions.first;
        if (!first.valid() || board[first.getX()][first.getY()])
        {            
            return false;
        }
        
        Position second = positions.second;
        if (!second.valid() || board[second.getX()][second.getY()])
        {            
            return false;
        }

        board[first.getX()][first.getY()]   = chessmen.size() + 1;
        board[second.getX()][second.getY()] = chessmen.size() + 1;

        chessmen.push(chessman);

        if (isFinished())
        {
            string solution = getSolutionString();
            result.insert(solution);
            cout<<"Solution Num : "<<result.size()<<endl;
            cout<<solution<<endl;
            cout<<"====================================="<<endl;
        }

        return true;
    }

    bool unhold(Chessman& pop)
    {
        pop = chessmen.top();
        board[pop.getPositions().first.getX()][pop.getPositions().first.getY()]   = 0;
        board[pop.getPositions().second.getX()][pop.getPositions().second.getY()] = 0;
        chessmen.pop();

        return true;
    }

    bool isHold(const Position& position) const
    {
        if (position.valid())
        {
            if (board[position.getX()][position.getY()])
            {
                return true;
            }
        }
        return false;
    }

    bool isFinished() const
    {
        return chessmen.size() == MAX_LENGTH * MAX_LENGTH / 2;
    }

    string getSolutionString()
    {
        ostringstream rtn;
        for (int i = 0; i < MAX_LENGTH; i++)
        {
            for (int j = 0; j < MAX_LENGTH; j++)
            {
                if (i != 0 && j == 0)
                {
                    rtn<<endl;
                }
                rtn.width(4);
                rtn<<board[i][j];                
            }
        }
        return rtn.str();
    }  
};

int main(int argc, char** argv)
{
    Chessboard board;

    bool done = false;
    for (int i = 0; i < MAX_LENGTH && !done; i++)
    {
        for (int j = 0; j < MAX_LENGTH && !done; j++)
        {
            if (!board.isFinished())
            {     
                Position currgrid(i, j);   
                if (board.isHold(currgrid))
                {
                    continue;
                }
                Chessman chessmanR(make_pair(currgrid, currgrid.getRight()));
                Chessman chessmanB(make_pair(currgrid, currgrid.getBottom()));

                if (board.hold(chessmanR) || board.hold(chessmanB))
                {
                    continue;
                }
            }

            while (true)
            {
                Chessman pop;
                board.unhold(pop);
                
                Position popposition = pop.getPositions().first;
                i = popposition.getX();
                j = popposition.getY();

                if (pop.isXdirection())
                {
                    Chessman change(make_pair(popposition, popposition.getBottom()));
                    if (board.hold(change))
                    {
                        break;
                    }
                }

                if (i == 0 && j == 0)
                {
                    done = true;
                    break;
                }
            }
        }
    }

    cout<<"OK, Done."<<endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值