马踏棋盘(回溯,贪心)

// HorseTransDlg.h : 头文件
//

#pragma once
#include <vector>

//typedef struct _StepState {
//    POINT pos;
//    //int childNum;
//    std::vector<_StepState*>* pChildTree;
//    //_StepState* preStep;
//} StepState;

template<class T>
class TreeNode
{
public:
    TreeNode() {
        parentNode = nullptr;
        index = -1;
        enable = 1;
        childrenTree.clear();
    }
    ~TreeNode() {}

    void releaseChildren()
    {
        int isize = childrenTree.size();
        if (isize == 0) {
            return;
        }
        for (int ii = isize-1; ii >= 0; --ii) {
            childrenTree[ii]->releaseChildren();
            delete childrenTree[ii];
        }
        childrenTree.clear();
    }
    void addChild(T* pStep)
    {
        childrenTree.push_back(pStep);
    }

    T* parentNode;
    int index;
    int enable;
    std::vector<T*> childrenTree;
};

class StepState :public TreeNode<StepState>
{
public:
    StepState(POINT _pos) {
        pos = _pos;
    }
    ~StepState() {}

    POINT pos;
};

// CHorseTransDlg 对话框
class CHorseTransDlg : public CDialogEx
{
// 构造
public:
    CHorseTransDlg(CWnd* pParent = NULL);    // 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_HORSETRANS_DIALOG };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持


// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()

    void paintBackground();
    int countNextStepsTree(StepState& curStep);

public:
    afx_msg void OnBnClickedBtnCalculate();
    afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
};
// HorseTransDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "HorseTrans.h"
#include "HorseTransDlg.h"
#include "afxdialogex.h"

#include <vector>
#include <list>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CHorseTransDlg 对话框
const int MARGIN_X = 10;
const int MARGIN_Y = 10;
const int FONT_MARGIN_X = 10;
const int FONT_MARGIN_Y = 10;
const int SPACE_X = 30;
const int SPACE_Y = 30;

// 这2个值可以随便改,形成不同的棋盘
const int BLOCKS_X = 16;
const int BLOCKS_Y = 10;

int g_Position[BLOCKS_Y][BLOCKS_X];
POINT g_startPos = {-1,-1};

CHorseTransDlg::CHorseTransDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_HORSETRANS_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CHorseTransDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CHorseTransDlg, CDialogEx)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BTN_CALCULATE, &CHorseTransDlg::OnBnClickedBtnCalculate)
    ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()


// CHorseTransDlg 消息处理程序

BOOL CHorseTransDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    //ShowWindow(SW_MINIMIZE);

    // TODO: 在此添加额外的初始化代码
    memset(g_Position, 0, sizeof(g_Position));
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CHorseTransDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
        paintBackground();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CHorseTransDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}

void CHorseTransDlg::paintBackground()
{
    CDC* pDC = GetDC();

    // 画棋盘
    int ii;
    for (ii = 0; ii <= BLOCKS_Y;++ii) {
        pDC->MoveTo(MARGIN_X, MARGIN_Y + ii*SPACE_Y);
        pDC->LineTo(MARGIN_X + BLOCKS_X*SPACE_X, MARGIN_Y + ii*SPACE_Y);
    }
    for (ii = 0; ii <= BLOCKS_X; ++ii) {
        pDC->MoveTo(MARGIN_X + ii*SPACE_X, MARGIN_Y);
        pDC->LineTo(MARGIN_X + ii*SPACE_X, MARGIN_Y + BLOCKS_Y*SPACE_Y);
    }

    // 画步骤号
    TCHAR buf[10];
    for (int ii = 0; ii < BLOCKS_Y; ii++) {
        for (int jj = 0; jj < BLOCKS_X; jj++) {
            if (g_Position[ii][jj] != 0) {
                _itot_s(g_Position[ii][jj], buf, 10);
                if (g_Position[ii][jj] == BLOCKS_X * BLOCKS_Y) {
                    // 结束标志
                    CRect rect(MARGIN_X + jj * SPACE_X, 
                        MARGIN_Y + ii * SPACE_Y,
                        MARGIN_X + (jj+1) * SPACE_X, 
                        MARGIN_Y + (ii+1) * SPACE_Y);
                    CBrush brush(RGB(255,0,0));
                    pDC->FillRect(&rect, &brush);
                }
                pDC->TextOut(MARGIN_X + jj * SPACE_X + FONT_MARGIN_X,
                            MARGIN_Y + ii * SPACE_Y + FONT_MARGIN_Y,
                            buf);
            }
        }
    }

    ReleaseDC(pDC);
}

void CHorseTransDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if (point.x < MARGIN_X || point.y < MARGIN_Y 
        || point.x >= MARGIN_X + BLOCKS_X*SPACE_X || point.y >= MARGIN_Y + BLOCKS_Y*SPACE_Y)
    {
        CDialogEx::OnLButtonDblClk(nFlags, point);
        return;
    }
    int iRectX = (point.x - MARGIN_X) / SPACE_X;
    int iRectY = (point.y - MARGIN_Y) / SPACE_Y;

    g_startPos = { iRectX, iRectY };

    memset(g_Position, 0, sizeof(g_Position[0][0]) * BLOCKS_Y * BLOCKS_X);
    g_Position[iRectY][iRectX] = 1;

    CDialogEx::OnLButtonDblClk(nFlags, point);
    Invalidate();
}

void CHorseTransDlg::OnBnClickedBtnCalculate()
{
    if (g_startPos.x < 0 || g_startPos.y < 0) {
        return;
    }

    int iStep = 1;
    int iAllStep = BLOCKS_X * BLOCKS_Y;

    POINT pos = g_startPos;
    StepState startStep(pos);
    StepState* pCurStep = &startStep;

    while (iStep < iAllStep) {

        while (iStep < iAllStep) {
            // 获取当前节点所有下一个节点集,简称一代节点集
            int iCount = countNextStepsTree(*pCurStep);

            // 获取当前节点每个一代节点的下代节点集,简称二代节点
            // 贪心算法,取二代节点数最小的一代节点做下一步
            int iMin = -1;
            for (int ii = 0; ii < iCount; ii++) {

                StepState* tempStep = pCurStep->childrenTree[ii];
                if (tempStep->enable == 0) {
                    continue;
                }
                int x = tempStep->pos.x;
                int y = tempStep->pos.y;
                g_Position[y][x] = iStep + 1;
                int num = countNextStepsTree(*tempStep);
                g_Position[y][x] = 0;

                if (num > 0) {
                    if (num < iMin || iMin < 0) {
                        iMin = num;
                        pCurStep->index = ii;
                    }
                }
            }

            // 选自身分支最少那个子分支
            if (pCurStep->index >= 0) {
                pCurStep = pCurStep->childrenTree[pCurStep->index];
                int iX = pCurStep->pos.x;
                int iY = pCurStep->pos.y;
                g_Position[iY][iX] = ++iStep;
            }else {
                if (iStep + 1 >= iAllStep && pCurStep->childrenTree.size() > 0) {
                    // 圆满完成
                    pCurStep = pCurStep->childrenTree[0];
                    int iX = pCurStep->pos.x;
                    int iY = pCurStep->pos.y;
                    g_Position[iY][iX] = ++iStep;
                }
                else {
                    // 走到死胡同
                    break;
                }
            }
        }

        if (iStep < iAllStep) {
            // 回溯
            do {
                pCurStep->enable = 0;
                int iX = pCurStep->pos.x;
                int iY = pCurStep->pos.y;
                g_Position[iY][iX] = 0;
                --iStep;
                pCurStep = pCurStep->parentNode;
                if (pCurStep == nullptr) {
                    MessageBox(_T("无解"));
                    break;
                }
                int iMin = -1;
                int iCount = pCurStep->childrenTree.size();
                pCurStep->index = -1;

                for (int ii = 0; ii < iCount; ii++) {
                    StepState* pState = pCurStep->childrenTree[ii];
                    if (pState->enable != 1) {
                        continue;
                    }
                    int iNum = pState->childrenTree.size();
                    if (iNum < iMin || iMin < 0) {
                        iMin = iNum;
                        pCurStep->index = ii;
                    }
                }
                if (pCurStep->index != -1) {
                    break;
                }
            } while (pCurStep != nullptr);

            if (pCurStep == nullptr) {
                break;
            }
        }
    }

    startStep.releaseChildren();
    g_startPos = {-1, -1};
    Invalidate();
}

int CHorseTransDlg::countNextStepsTree(StepState& curStep)
{
    if (curStep.pos.x == -1 || curStep.pos.y == -1) {
        return 0;
    }
    int iCount = curStep.childrenTree.size();
    if (iCount > 0){
        return iCount;
    }

    int x = curStep.pos.x;
    int y = curStep.pos.y;

    if (x + 2 < BLOCKS_X && y + 1 < BLOCKS_Y && x + 2 >= 0 && y + 1 >= 0) {
        POINT newPoint = { x + 2, y + 1 };
        if (g_Position[newPoint.y][newPoint.x] == 0) {
            StepState* state = new StepState(newPoint);
            state->parentNode = &curStep;
            curStep.childrenTree.push_back(state);
        }
    }
    if (x + 2 < BLOCKS_X && y - 1 < BLOCKS_Y && x + 2 >= 0 && y - 1 >= 0) {
        POINT newPoint = { x + 2, y - 1 };
        if (g_Position[newPoint.y][newPoint.x] == 0) {
            StepState* state = new StepState(newPoint);
            state->parentNode = &curStep;
            curStep.childrenTree.push_back(state);
        }
    }
    if (x + 1 < BLOCKS_X && y + 2 < BLOCKS_Y && x + 1 >= 0 && y + 2 >= 0) {
        POINT newPoint = { x + 1, y + 2 };
        if (g_Position[newPoint.y][newPoint.x] == 0) {
            StepState* state = new StepState(newPoint);
            state->parentNode = &curStep;
            curStep.childrenTree.push_back(state);
        }
    }
    if (x + 1 < BLOCKS_X && y - 2 < BLOCKS_Y && x + 1 >= 0 && y - 2 >= 0) {
        POINT newPoint = { x + 1, y - 2 };
        if (g_Position[newPoint.y][newPoint.x] == 0) {
            StepState* state = new StepState(newPoint);
            state->parentNode = &curStep;
            curStep.childrenTree.push_back(state);
        }
    }
    if (x - 2 < BLOCKS_X && y + 1 < BLOCKS_Y && x - 2 >= 0 && y + 1 >= 0) {
        POINT newPoint = { x - 2, y + 1 };
        if (g_Position[newPoint.y][newPoint.x] == 0) {
            StepState* state = new StepState(newPoint);
            state->parentNode = &curStep;
            curStep.childrenTree.push_back(state);
        }
    }
    if (x - 2 < BLOCKS_X && y - 1 < BLOCKS_Y && x - 2 >= 0 && y - 1 >= 0) {
        POINT newPoint = { x - 2, y - 1 };
        if (g_Position[newPoint.y][newPoint.x] == 0) {
            StepState* state = new StepState(newPoint);
            state->parentNode = &curStep;
            curStep.childrenTree.push_back(state);
        }
    }
    if (x - 1 < BLOCKS_X && y + 2 < BLOCKS_Y && x - 1 >= 0 && y + 2 >= 0) {
        POINT newPoint = { x - 1, y + 2 };
        if (g_Position[newPoint.y][newPoint.x] == 0) {
            StepState* state = new StepState(newPoint);
            state->parentNode = &curStep;
            curStep.childrenTree.push_back(state);
        }
    }
    if (x - 1 < BLOCKS_X && y - 2 < BLOCKS_Y && x - 1 >= 0 && y - 2 >= 0) {
        POINT newPoint = { x - 1, y - 2 };
        if (g_Position[newPoint.y][newPoint.x] == 0) {
            StepState* state = new StepState(newPoint);
            state->parentNode = &curStep;
            curStep.childrenTree.push_back(state);
        }
    }

    return curStep.childrenTree.size();
}

 

posted on 2020-10-17 23:17  litandy  阅读(126)  评论(0编辑  收藏  举报

导航