马踏棋盘(回溯,贪心)
// 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(); }