zoukankan      html  css  js  c++  java
  • 搜索入门练习题6 马的遍历 题解

    题目出处:《信息学奥赛一本通》例5.5

    题目描述

    中国象棋半张棋盘如图(a)所示。马自左下角往右上角跳。今规定只许往右跳,不许往左跳。比如(a)中所示为一种跳行路线,并将所经路线打印出来。打印格式为:

    0,0->2,1->3,3->1,4->3,5->2,7->4,8……
    

    提示:马每一步最多有 (4) 个方向可以走,如图(b)所示。

    输出格式

    输出马行走的所有方案,每个方案按照题目描述占一行。

    题目分析

    使用深度优先搜索可以解决这个问题。
    如图(b)所示,马最多有四个方向,若原来的横坐标为 (j) 、纵坐标为 (i) ,则四个方向的移动可表示为:

    • 1: ((i,j) ightarrow (i+2,j+1))((i lt 3,j lt 8))
    • 2: ((i,j) ightarrow (i+1,j+2))((i lt 4,j lt 7))
    • 3: ((i,j) ightarrow (i-1,j+2))((i gt 0,j lt 7))
    • 4: ((i,j) ightarrow (i-2,j+1))((i gt 1, j lt 8))

    深度优先搜索的搜索策略可以有很多种,但本质还是状态之间的转换。
    我们用 ((i,j)) 表示横坐标为 (j) ,纵坐标为 (i) 时的马的状态。一开始马在 ((0,0)) ,它最终要走到 ((4,8))
    因为马每次最少往右边走一格,所以马行走的步数最多八步。我们开两个数组 ansx[]ansy[] 来存储马每一步的状态,一开始ansx[0] = ansy[0] = 0,表示第 (0) 步的时候马处在 ((0,0)) 位置,我们使用函数 f(int id) 用于表示第 id 步时马的放置方案。
    如果马此时的放置位置 ((x,y)) 满足 (y = 8)的条件,那么我们:

    • 看一下 (x) 是不是等于 (4) ,如果是的话则说明走到了终点,输出方案;
    • 否则就说明马走到最右边的格子但不是 ((4,8)) ,说明这条路不可行,返回。

    如果 (y lt 8) ,说明还没有走到最右边,继续扩展新的状态。
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    // (ansx[i],ansy[i])用于记录第i步的状态
    // dir数组用于表示马要行走的四个方向
    int ansx[9], ansy[9];
    int dir[4][2] = { 2, 1, 1, 2, -1, 2, -2, 1 };
    // in_map函数用于确定(x,y)是否超出了棋盘边界
    bool in_map(int x, int y) {
        return x >= 0 && x <= 4 && y >= 0 && y <= 8;
    }
    // output函数用于从第0步输出到第id步的方案
    void output(int id) {
        cout <<"0,0";
        for (int i = 1; i <= id; i ++)
            cout << "->" << ansx[i] << "," << ansy[i];
        cout << endl;
    }
    // f函数用于搜索遍历所有的方案
    void f(int id) {
        int x1 = ansx[id], y1 = ansy[id];   // (x1, y1) 用于表示当前马的状态
        if (y1 == 8) {  // 说明已经到达最右边的那一列了
            if (x1 == 4) {  // 说明走到了终点 (4,8)
                output(id);
            }
            // else // 其他情况不用输出,直接退出就可以了
            return;
        }
        for (int i = 0; i < 4; i ++) {  // 遍历4个方向
            int x2 = x1 + dir[i][0];
            int y2 = y1 + dir[i][1];    // (x2,y2)是(x1,y1)能走到的4个点之一
            if (in_map(x2,y2)) {
                ansx[id+1] = x2;  // 将ansx[id+1]更新为x2
                ansy[id+1] = y2;  // 将ansy[id+1]更新为y2
                f(id+1);        // 设置到第id+1步再进f(id+1)去设置第id+2步
            }
        }
    }
    int main() {
        f(0); // 从(0,0)开始扩展状态
        return 0;
    }
    

    注意:我这里是按照图(b)中1、2、3、4的顺序优先走的,实际搜索是按照相关规则就该程序中的dir数组即可。

  • 相关阅读:
    第2季:从官方例程深度学习海思SDK及API
    H.264帧结构详解
    Linux内核链表
    在Sqlite中通过Replace来实现插入和更新
    mysql 里随机生成时间
    搭建Cordova + Ionic + WebStorm环境开发Web App应用
    Angular Local Storage 使用方法
    angularJS中controller与directive双向通信
    ui-router传递参数
    Sequelize 和 MySQL 对照
  • 原文地址:https://www.cnblogs.com/zifeiynoip/p/11450708.html
Copyright © 2011-2022 走看看