算法之一:老掉牙的问题

搜索有以下几种算法: 枚举算法: 也即列举问题的所有状态从而寻找符合问题的解的方法。 适合用于状态较少,比较简单的问题上。 广度优先搜索: 从初始点开始,根据规则展开第一层节点,并检查目标节点是否在这些节点上,若没有,再将所有的第一层的节点逐一展开,得到第二层节点,如没有,则扩展下去,直到发现目标节点为止。 比较适合求最少步骤或最短解序列的题目。 一
摘要由CSDN通过智能技术生成

搜索有以下几种算法:

  • 枚举算法:
    • 也即列举问题的所有状态从而寻找符合问题的解的方法。
    • 适合用于状态较少,比较简单的问题上。
  • 广度优先搜索:
    • 从初始点开始,根据规则展开第一层节点,并检查目标节点是否在这些节点上,若没有,再将所有的第一层的节点逐一展开,得到第二层节点,如没有,则扩展下去,直到发现目标节点为止。
    • 比较适合求最少步骤或最短解序列的题目。
    • 一般设置一个队列queue,将起始节点放入队列中,然后从队列头取出一个节点,检查是否是目标节点,如不是则进行扩展,将扩展出的所有节点放到队尾,然后再从队列头取出一个节点,直至找到目标节点。
  • 深度优先搜索:
    • 一般设置一个栈stack,将起始节点放入栈中,然后从栈中弹出一个节点,检查是否是目标节点,如不是则进行扩展,将扩展出的所有节点入栈,然后再从栈顶弹出一个节点,直到找到目标节点。
    • 深度优先搜索得到的第一个解,不一定是最优解。
  • 双向广度优先搜索:
    • 双向搜索:从起始节点向目标节点方向搜索,同时从目标节点向起始节点方向搜索。
    • 双向搜索只能用于广度优先搜索中。
    • 双向搜索扩展的节点数量要比单向少的多。
  • A*算法
    • 利用问题的规则和特点来制定一些启发规则,由此来改变节点的扩展顺序,将最有希望扩展出最优解的节点优先扩展,使得尽快找到最优解。
    • 对每一个节点,有一个估价函数F来估算起始节点经过该节点到达目标节点的最佳路径的代价。
    • 每个节点扩展的时候,总是选择具有最小的F的节点。
    • F=G+B×H:G为从起始节点到当前节点的实际代价,已经算出,H为从该节点到目标节点的最优路径的估计代价。F要单调递增。
    • B最好随着搜索深度成反比变化,在搜索深度浅的地方,主要让搜索依靠启发信息,尽快的逼近目标,而当搜索深的时候,逐渐变成广度优先搜索。
  • 回溯算法:
    • 和深度优先相似,不同之处在于对一个节点扩展的时候,并不将所有的子节点扩展出来,而只扩展其中的一个。因而具有盲目性,但内存占用少。
  • 搜索中的优化:
    • 在搜索前,根据条件降低搜索规模。
    • 广度优先搜索中,被处理过的节点,充分释放空间。
    • 给据问题的约束条件进行剪枝。
    • 利用搜索过程中的中间解,避免重复计算。

 

一、马的走法

题目:

在一个4X5的棋盘上,马的起始坐标由用户输入,求马返回初始位置的所有不同的走法的总数和步骤。马走过的位置不能重复。

 

//Chess.h

#include
using namespace std;

class Chess
{
public:
    Chess(int w, int h):width(w),height(h)
    {
        chess = new int*[w];
        for(int i = 0; i < w; i++){
            chess[i] = new int[h];
            for(int j=0; j < h; j++){
                chess[i][j] = 0;
            }
        }
    }

    int FindPath(int startx, int starty);
protected:
private:

    const static int stepx[8];   
    const static int stepy[8];

    int ** chess;
    int width;
    int height;

    struct Pos {
        Pos():x(0), y(0){}
        Pos(int _x, int _y):x(_x), y(_y){}
        int x;
        int y;
    };

    Pos startp;

    void jump(int posx, int posy, int &count, vector &path);
};

//Chess.cpp

#include "Chess.h"

const int Chess::stepx[8]={-2, -1, 1, 2, 2, 1, -1, -2};
const int Chess::stepy[8]={1, 2, 2, 1, -1, -2, -2, -1};

int Chess::FindPath(int startx, int starty)
{
    for(int i = 0; i < width; i++)
        for(int j=0; j < height; j++)
            chess[i][j] = 0;
    startp.x = startx;
    startp.y = starty;
    vector path;
    int count = 0;
    chess[startx][starty] = 1;
    Pos p(startx, starty);
    path.push_back(p);
    jump(startx, starty, count, path);
    return count;
}

void Chess::jump(int posx, int posy, int &count, vector &path)
{
    for(int i = 0; i < 8; i++){
        int nextx = posx + stepx[i];
        int nexty = posy + stepy[i];
        if (nextx >= 0 && nextx < width && nexty >= 0 && nexty < height && chess[nextx][nexty] == 0) {
            chess[nextx][nexty] = 1;
            Pos p(nextx, nexty);
            path.push_back(p);
            jump(nextx,nexty,count,path);
            path.pop_back();
            chess[nextx][nexty] = 0;
        } else if (nextx == startp.x && nexty == startp.y) {
            count++;
            Pos p(nextx, nexty);
            path.push_back(p);
            printf("The %dth path : ", count);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值