C++八数码问题算法或策略比较[2025-11-17]

大作业要求
内容
一般要求
大作业 1
1 一般要求
(1)文档部分(含源代码风格)
描述问题。包括:题目、任务、环境、感知、动作、评价标准、算法等。
算法。可以仿照书上的算法。
实验结果。包括细节,例如:统计结果。可以通过图、表等展示。还包括平均或统计结果等。
分析。例如:解的最优性、时间复杂度、空间复杂度、有效分支因子等。
1 一般要求
结论。用几句话、或一个自然段描述。
源代码风格:函数、变量命名是否规范。源代码排版是否合理等。
按照 A4 纸排版(可以一页或多页),签上姓名、学号,打印或手写后交给助教。
教师评分标准:是否全面?是否准确?是否有错别字?是否有错误?表格、图形是否清晰?如果不全面或存在错误、错别字,则扣分较多。
评价:可以仿照学术论文的格式,但是只要骨架即可。
1 一般要求
(2)源代码部分
在助教给出的 VS 项目上完成必须的一个或多个函数。
根据助教给出的输入参数运行程序、并记录运行结果。
在可正确运行后,将自己完成的一个或多个函数打包、提交给助教。
助教针对每个函数至少运行一次,以检查程序的正确性。
评价:要求同学们独立完成。如果有困难,则可以参考其他同学的答案,但是不要抄袭
1 一般要求
评分标准:如果编译不能通过,且是由于同学的错误或失误造成,则没有分数。如果某函数不能执行、或结果错误,则该函数没有分数。
2 大作业 1:八数码问题算法或策略比较
算法 1:广度优先
算法 2:深度有限。深度限定为 5-20
算法 3:启发式搜索。启发式函数采用不正确位置的数码个数
算法 4:启发式搜索。启发式函数采用到目标位置的曼哈顿距离之和。
框架:目标状态,如下图。

2 大作业 1:八数码问题算法或策略比较
起始状态:输入参数回退步数,一般为 backward_moves=5-20 步,框架基于随机数回退。
调试:在屏幕上动态输出移动过程。并最后给出实际移动步数和结果是否正确。例如:forward-moves=7 result=correct 或 wrong。
调试设置:setup=1 广度优先
2 深度有限
3 启发式搜索。启发式函数 1
4 启发式搜索。启发式函数 2
2 大作业 1:八数码问题算法或策略比较
交作业时间:第九周周五之前。电子版源代码发给助教老师,纸质版文档交给助教老师。如果推迟的话,则分数减半,请大家注意。
评分标准:4 个函数,各 2 分。文档:1 分。源代码风格:1 分。一共 10 分。

源码联系UP主 -> https://space.bilibili.com/329101171

eightFigurePuzzles.h代码

#pragma once
#include <iostream>
#include <vector>
using namespace std;
const int puzzleNum = 8;
/*
*描述:记录8数码九宫格内每一个格子对应的位置信息与存放的数码。
* xPosition :行数 0 代表第一行
* yPosition: 列数 0 代表第一行
* puzzleId: 数码 0~8
*/
typedef struct {
    int xPosition;
    int yPosition;
    int puzzleId;
} PUZZLE;

/*
*描述:声明一个节点,存储当前九宫格状态
*      以目标状态为例,puzzle: {{0,0,0},{0,1,1},{0,2,2},
						   {1,0,3},{1,1,4},{1,2,5},
						   {2,0,6},{2,1,7},{2,2,8},}

				  nextActionList: {[1,0]    向上移动
								   [-1,0]   向下移动
								   [0,1]    向左移动
								   [0.-1]}  向右移动

				  nextAxtionList的大小<=4

				  depth: 当前状态所处深度
*/
typedef struct {
    //vector<PUZZLE> puzzles;
    PUZZLE puzzle[9];
    vector<vector<int>> nextActionList;
    vector<vector<int>> precedeActionList;
    int depth;
} PUZZLE_NODE;

/*
* 输入:节点状态puzzleNode
* 输出  空格位置,二维数组。
* 描述:找到 空格 0 所在的位置,返回1个2维数组,分别代表行数和列数;
*/
int* findZeroPosition(PUZZLE_NODE puzzleNode);

/*
*
* 输入:节点状态puzzleNode
* 输出:actionList初始化后的puzzleNode
*描述:更新puzzleNode的后继可操作动作状态,其中 (1,0)代表空格向上移动,(-1,0)代表空格向下移动,(0,1)代表空格向左移动,(0,-1)代表空格向右移动。
*/
PUZZLE_NODE updatePuzzleNodeActionList(PUZZLE_NODE puzzleNode);

/*
* 输入:给定动作数组,例如[1,0],代表空格向上移动
* 输出:puzzleNode在执行完输入动作后得到的新的数码状态
* 描述:给定动作action(action为二维数组)和puzzleNode,返回执行该动作后新的节点
*/
PUZZLE_NODE moveToPuzzleNode(vector<int> action, PUZZLE_NODE puzzleNode);

/*
* 输入:puzzleNode的后继动作数量的大小
* 输出:随机动作索引
* 描述:用于生成PuzzleNode中随机动作索引,用于随机后退。
*/
int getRandomNumber(int actionSize);

/*
* 输入:puzzle1:当前状态某一位置上的状态,puzzle2:目标状态某一位置上的状态
* 输出:true:相等 false:不相等
* 描述:判断当前节点状态和目标节点状态在同一位置上两个8数码状态是否相同。
*/
bool isEqual(PUZZLE puzzle1, PUZZLE puzzle2);

/*
* 输入:当前数码节点状态currentNode,目标数码节点状态objNode
* 输出:两个节点状态是否匹配,如果匹配,说明找到目标状态,返回true;
*                             如果不匹配,说明还未找到目标状态,返回false;
*描述:检测当前节点和目标节点状态是否相同。
*/
bool checkObject(PUZZLE_NODE currentNode, PUZZLE_NODE objNode);

/*
* 输入:回退步数
* 输出:给定目标状态回退backwardSteps后的初始状态
* 描述:给定回退步数,返回初始节点状态
*/
PUZZLE_NODE initialPuzzleNode(int backwardSteps);

/*
* 输入:动作
* 输出:给定目标状态回退backwardSteps后的初始状态
* 描述:输出动作
*/
void outputAction(vector<int> action, int index);

//用于生成当前状态对应的唯一数字,用于eightFigureFramework中visited判断当前节点状态是否访问过。
int visitedNum(PUZZLE_NODE puzzleNode);

eightFigurePuzzles.cpp 代码

#include "eightFigurePuzzles.h"
#include <time.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

//找到 空格 0 所在的位置
int* findZeroPosition(PUZZLE_NODE puzzleNode) {
    int* res = new int[2]{0, 0};
    for (int i = 0; i < puzzleNum + 1; i++) {
        if (puzzleNode.puzzle[i].puzzleId == 0) {
            res[0] = puzzleNode.puzzle[i].xPosition;
            res[1] = puzzleNode.puzzle[i].yPosition;
            return res;
        }
    }
    return res;
}

//更新puzzleNode的后继可操作动作状态,其中 (1,0)代表空格向上移动,(-1,0)代表空格向下移动,(0,1)代表空格向左移动,(0,-1)代表空格向右移动。
PUZZLE_NODE updatePuzzleNodeActionList(PUZZLE_NODE puzzleNode) {
    int* xyPosition = findZeroPosition(puzzleNode);
    int x = xyPosition[0];
    int y = xyPosition[1];
    delete [] xyPosition;
    if (x >= 1) {
        vector<int> actionUp;
        actionUp.push_back(1);
        actionUp.push_back(0);
        puzzleNode.nextActionList.push_back(actionUp);
    }
    if (x <= 1) {
        vector<int> actionDown;
        actionDown.push_back(-1);
        actionDown.push_back(0);
        puzzleNode.nextActionList.push_back(actionDown);
    }
    if (y >= 1) {
        vector<int> actionLeft;
        actionLeft.push_back(0);
        actionLeft.push_back(1);
        puzzleNode.nextActionList.push_back(actionLeft);
    }
    if (y <= 1) {
        vector<int> actionRight;
        actionRight.push_back(0);
        actionRight.push_back(-1);
        puzzleNode.nextActionList.push_back(actionRight);
    }
    return puzzleNode;
}

void outputAction(vector<int> action, int index) {
    /*cout << action[0] << " " << action[1] << endl;*/
    if (action[0] == 1 && action[1] == 0) {
        cout << "步数 " << index << ":向上移动" << endl;
        cout << endl;
    } else if (action[0] == -1 && action[1] == 0) {
        cout << "步数 " << index << "向下移动" << endl;
        cout << endl;
    } else if (action[0] == 0 && action[1] == 1) {
        cout << "步数 " << index << "向左移动" << endl;
        cout << endl;
    } else {
        cout << "步数 " << index << "向右移动" << endl;
        cout << endl;
    }
}

// 给定动作action(action为二维数组)和puzzleNode,返回执行该动作后新的节点
PUZZLE_NODE moveToPuzzleNode(vector<int> action, PUZZLE_NODE puzzleNode) {
    //cout << action[0] << " " << action[1] << endl;
    //if (action[0] == 1 && action[1] == 0) {
    //	cout << "向上移动" << endl;
    //}
    //else if (action[0] == -1 && action[1] == 0) {
    //	cout << "向下移动" << endl;
    //}
    //else if (action[0] == 0 && action[1] == 1) {
    //	cout << "向左移动" << endl;
    //}
    //else {
    //	cout << "向右移动" << endl;
    //}

    int* xyPosition = findZeroPosition(puzzleNode);
    int x = xyPosition[0];
    int y = xyPosition[1];
    delete [] xyPosition;
    PUZZLE_NODE nextPuzzleNode;
    for (int xPos = 0; xPos < 3; xPos++) {
        for (int yPos = 0; yPos < 3; yPos++) {
            nextPuzzleNode.puzzle[xPos * 3 + yPos].xPosition = xPos;
            nextPuzzleNode.puzzle[xPos * 3 + yPos].yPosition = yPos;
            if (xPos == x && yPos == y) {
                nextPuzzleNode.puzzle[xPos * 3 + yPos].puzzleId = puzzleNode.puzzle[((x - action[0]) * 3 + (y - action[1]))].puzzleId;
            } else if (xPos == (x - action[0]) && yPos == (y - action[1])) {
                nextPuzzleNode.puzzle[xPos * 3 + yPos].puzzleId = puzzleNode.puzzle[(x * 3 + y)].puzzleId;
            } else {
                nextPuzzleNode.puzzle[xPos * 3 + yPos].puzzleId = puzzleNode.puzzle[xPos * 3 + yPos].puzzleId;
            }
        }
    }
    return nextPuzzleNode;
}

// 用于生成PuzzleNode中随机动作索引
int getRandomNumber(int actionSize) {
    return rand() % actionSize;
}

//给定回退步数,返回初始状态
PUZZLE_NODE initialPuzzleNode(int backwordSteps) {
    PUZZLE_NODE objNode;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            objNode.puzzle[i * 3 + j].puzzleId = i * 3 + j;
            objNode.puzzle[i * 3 + j].xPosition = i;
            objNode.puzzle[i * 3 + j].yPosition = j;
        }
    }
    PUZZLE_NODE initialPuzzleNode = updatePuzzleNodeActionList(objNode);
    srand((unsigned)time(0));  //time()用系统时间初始化种。为rand()生成不同的随机种子。
    for (int i = 0; i < backwordSteps; i++) {
        PUZZLE_NODE precedePuzzleNode = initialPuzzleNode;
        int action = getRandomNumber(initialPuzzleNode.nextActionList.size());
        initialPuzzleNode = moveToPuzzleNode(initialPuzzleNode.nextActionList[action], initialPuzzleNode);
        initialPuzzleNode = updatePuzzleNodeActionList(initialPuzzleNode);
    }
    initialPuzzleNode = updatePuzzleNodeActionList(initialPuzzleNode);
    return initialPuzzleNode;
}

//判断两个8数码状态是否相同
bool isEqual(PUZZLE puzzle1, PUZZLE puzzle2) {
    if (puzzle1.xPosition == puzzle2.xPosition && puzzle1.yPosition == puzzle2.yPosition && puzzle1.puzzleId == puzzle2.puzzleId)
        return true;
    else
        return false;
}

//检测当前节点和目标节点状态是否相同
bool checkObject(PUZZLE_NODE currentNode, PUZZLE_NODE objNode) {
    for (int i = 0; i < puzzleNum + 1; i++) {
        if (!isEqual(currentNode.puzzle[i], objNode.puzzle[i]))
            return false;
    }
    return true;
}

//判断当前节点状态是否被访问过。
int visitedNum(PUZZLE_NODE puzzleNode) {
    int mapValue = 0;

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            mapValue = mapValue * 10 + puzzleNode.puzzle[i * 3 + j].puzzleId;
        }
    }
    return mapValue;
}

eightFigurePuzzlesFramework.cpp 代码

#include <time.h>
#include <windows.h>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
#include "eightFigurePuzzles.h"
using namespace std;

//用于记录当前状态是否被访问过。
map<int, int> visited;

//深度有限搜索,用于限制深度。
#define MAX_DEPTH 20

//openList与closeList用于A*搜索。
vector<PUZZLE_NODE> closeList;
vector<PUZZLE_NODE> openList;

//广度优先搜索
int* binaryFirstSearch(PUZZLE_NODE initialNode, PUZZLE_NODE objPuzzleNode) {
    //result[0] 1:correct;0:wrong
    //result[1] 步数 steps
    int* result = new int[2]{0, 0};

    /*
		请在该位置完成广度优先搜索。
	*/

    if (checkObject(initialNode, objPuzzleNode)) {
        result[0] = 1;
    } else {
        result[0] = 0;
    }

    return result;
}

//深度有限搜索
int* depthFirstSearch(PUZZLE_NODE initialNode, PUZZLE_NODE objPuzzleNode) {
    //result[0] 1:correct;0:wrong
    //result[1] 步数 steps
    int* result = new int[2]{0, 0};
    /*
		请在该位置完成深度有限搜索,最大深度限度为25。
	*/

    if (checkObject(initialNode, objPuzzleNode) && initialNode.depth < MAX_DEPTH) {
        result[0] = 1;
    } else {
        result[0] = 0;
    }

    return result;
}

//启发式搜索1
int* heuristicSearchInformedByIncorrectNum(PUZZLE_NODE initialNode, PUZZLE_NODE objPuzzleNode) {
    //result[0] 1:correct;0:wrong
    //result[1] 步数 steps
    int* result = new int[2]{0, 0};

    /*
		请在该位置完成启发式搜索,启发式函数使用不正确位置的数码个数。
	*/

    if (checkObject(initialNode, objPuzzleNode)) {
        result[0] = 1;
    } else {
        result[0] = 0;
    }

    return result;
}

//启发式搜素2
int* heuristicSearchInformedByManhattonDis(PUZZLE_NODE initialNode, PUZZLE_NODE objPuzzleNode) {
    //result[0] 1:correct;0:wrong
    //result[1] 步数 steps
    int* result = new int[2]{0, 0};
    /*
		请在该位置完成启发式搜索,启发式函数采用到目标位置的曼哈顿距离。
	*/

    if (checkObject(initialNode, objPuzzleNode)) {
        result[0] = 1;
    } else {
        result[0] = 0;
    }

    return result;
}

//广度优先搜索
int* binaryFirstSearchDemo(PUZZLE_NODE initialNode, PUZZLE_NODE objPuzzleNode) {
    //result[0] 1:correct;0:wrong
    //result[1] 步数 steps
    int* result = new int[2]{0, 0};

    cout << "初始节点状态:" << endl;
    for (int i = 0; i < 3; i++) {
        cout << " " << initialNode.puzzle[i * 3 + 0].puzzleId << "  " << initialNode.puzzle[i * 3 + 1].puzzleId << "  " << initialNode.puzzle[i * 3 + 2].puzzleId << endl;
    }
    cout << endl;
    /*
		请在该位置完成广度优先搜索函数。
	*/
    PUZZLE_NODE puzzleNode = initialNode;
    queue<PUZZLE_NODE> puzzleNodeQueue;
    puzzleNode.depth = 0;
    int depth = 0;
    puzzleNodeQueue.push(puzzleNode);
    while (puzzleNodeQueue.size()) {
        PUZZLE_NODE currentPuzzleNode = puzzleNodeQueue.front();
        if (checkObject(currentPuzzleNode, objPuzzleNode)) {
            for (int i = 0; i < currentPuzzleNode.precedeActionList.size(); i++) {
                outputAction(currentPuzzleNode.precedeActionList[i], i + 1);
            }
            cout << "找到正确结果:" << endl;
            for (int i = 0; i < 3; i++) {
                cout << " " << currentPuzzleNode.puzzle[i * 3 + 0].puzzleId << "  " << currentPuzzleNode.puzzle[i * 3 + 1].puzzleId << "  " << currentPuzzleNode.puzzle[i * 3 + 2].puzzleId << endl;
            }
            cout << endl;

            result[0] = 1;
            result[1] = currentPuzzleNode.depth;
            return result;
        } else {
            visited[visitedNum(currentPuzzleNode)] = 1;
            if (currentPuzzleNode.nextActionList.size() == 0) {
                currentPuzzleNode = updatePuzzleNodeActionList(currentPuzzleNode);
            }
            puzzleNodeQueue.pop();
            for (int i = 0; i < currentPuzzleNode.nextActionList.size(); i++) {
                PUZZLE_NODE nextPuzzleNode = moveToPuzzleNode(currentPuzzleNode.nextActionList[i], currentPuzzleNode);
                if (!currentPuzzleNode.precedeActionList.empty()) {
                    for (int actionIndex = 0; actionIndex < currentPuzzleNode.precedeActionList.size(); actionIndex++) {
                        nextPuzzleNode.precedeActionList.push_back(currentPuzzleNode.precedeActionList[actionIndex]);
                    }
                }
                nextPuzzleNode.precedeActionList.push_back(currentPuzzleNode.nextActionList[i]);
                if (visited[visitedNum(nextPuzzleNode)] == 1) {
                    continue;
                }
                nextPuzzleNode.depth = currentPuzzleNode.depth + 1;
                puzzleNodeQueue.push(nextPuzzleNode);
            }
        }
    }
    return result;
}

int main() {
    PUZZLE_NODE objPuzzleNode;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            objPuzzleNode.puzzle[i * 3 + j].puzzleId = i * 3 + j;
            objPuzzleNode.puzzle[i * 3 + j].xPosition = i;
            objPuzzleNode.puzzle[i * 3 + j].yPosition = j;
        }
    }
    objPuzzleNode = updatePuzzleNodeActionList(objPuzzleNode);

    int setup = 0;
    while (setup != -1) {
        visited.clear();

        cout << "请输入调试设置(-1:退出; 0:广度优先搜索示例;1:广度优先搜索;2:深度有限搜索;3:启发式搜索1;4:启发式搜索2):" << endl;
        cin >> setup;
        int backwardSteps;
        cout << "请输入大于等于5小于等于20的回退步数" << endl;
        cin >> backwardSteps;
        while (backwardSteps < 5 || backwardSteps > 20) {
            cout << "输入错误,请输入大于等于5小于等于20的回退步数" << endl;
            cin >> backwardSteps;
        }

        PUZZLE_NODE initialNode = initialPuzzleNode(backwardSteps);

        int* result;
        if (setup == 1) {
            result = binaryFirstSearch(initialNode, objPuzzleNode);
        } else if (setup == 2) {
            result = depthFirstSearch(initialNode, objPuzzleNode);
        } else if (setup == 3) {
            result = heuristicSearchInformedByIncorrectNum(initialNode, objPuzzleNode);
        } else if (setup == 4) {
            result = heuristicSearchInformedByManhattonDis(initialNode, objPuzzleNode);
        } else if (setup == 0) {
            cout << "广度优先搜索示例程序" << endl;
            result = binaryFirstSearchDemo(initialNode, objPuzzleNode);
        } else {
            cout << "输入设置有误,请重新运行" << endl;
            return 0;
        }

        if (result[0] == 1) {
            cout << "结果为correct,步数为" << result[1] << endl;
        } else {
            cout << "结果为wrong" << endl;
        }
        delete [] result;
    }
    return 0;
}
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐