sicily 1153. 马的周游问题

一、题目描述

在一个8 * 8的棋盘中的某个位置有一只马,如果它走29步正好经过除起点外的其他位置各一次,这样一种走法则称马的周游路线,试设计一个算法,从给定的起点出发,找出它的一条周游路线。

为了便于表示一个棋盘,我们按照从上到下,从左到右对棋盘的方格编号,如下所示:

1     2     3       4     5     6       7     8

9     10       11    12       13    14       15    16

17    18       19    20       21    22       23    24

25    26       27    28       29    30       31    32

33    34       35    36       37    38       39    40

41    42       43    44       45    46       47    48

49    50       51    52       53    54       55    56

57    58       59    60       61    62       63    64

马的走法是“日”字形路线,例如当马在位置15的时候,它可以到达2、4、7、11、19、23、26和28。但是规定马是不能跳出棋盘外的,例如从位置1只能到达9和14。

Input

输入有若干行。每行一个整数N(1<=N<=30),表示马的起点。最后一行用-1表示结束,不用处理。

Output

对输入的每一个起点,求一条周游线路。对应地输出一行,有30个整数,从起点开始按顺序给出马每次经过的棋盘方格的编号。相邻的数字用一个空格分开。

Sample Input

4

-1

Sample Output

注意:如果起点和输入给定的不同,重复多次经过同一方格或者有的方格没有被经过,都会被认为是错误的。

二、算法思想及主要数据结构

  • 算法思想:这题使用 dfs 来找到一条路径,因为根据题目描述可以看出路径的深度并不会很大,所以采用深搜是一种比较好的方法。使用递归来达到深搜。
  • 主要数据结构:这里使用结构体来保存节点内部值,使用 vector 来保存节点。

三、详细解题思路

  1. 首先因为棋盘的大小变大了,这个时候完全不剪枝的深搜显然会超时。根据树的结构可以知道,减少上层子节点,则下层子节点数也会相应减少。所以这里的一个思路就是保证先走可扩展位置比较少的位置,可扩展就是说如果当前节点是该节点,那么其可以走的下一个节点的数目。所以这里先求得下一个可能走的节点的可扩展位置数,然后根据位置数进行一个排序,优先走位置数较少的位置。

2.   位置处理,因为原棋盘的位置表示是用一个数字来表示的,这样对于我们的操作并不适合,所以将棋盘的代表数字转成一个 8 * 8 数组的下标来处理:

x = (N - 1) / 8;

y = (N - 1) % 8;

3.   马的移动分析:因为马必须走“日”型的路线,所以马的最多移动位置会有 8 个,分别是如下:

position(-1, 2), position(-2, 1), position(-2, -1), position(-1, -2),

position(1, -2), position(2, -1), position(2, 1), position(1, 2)

那么在每次移动后都可能有 8 个位置,需要对这些位置进行有效性判断:

bool isValid(int x, int y) {

return x >= 0 && y >= 0 && x <= 7 && y <= 7;

}

也即位置一定要在棋盘内。

4.   路径记录:因为一定会在 64 步内得到结果,那么也就是说每一步代表一个位置,那么只需要用一个含 64 个元素的数组来记录位置就可以。

int route[64];

在走一条新的路径的时候,只需要将步数对应位置的数字改成对应新位置的数字就可以:

route[step] = 8 * yTemp + xTemp + 1;

5.    在每个当前位置,会取得其可能走的下一个位置,在得到这些位置后再一这些位置为当前节点去看其可能的扩展位置的数目,根据这个数目进行排序,保存在一个vector里面,然后从该 vector 里面找下一个位置即可

if (isValid(xTemp, yTemp)) {

int canMovePoisitionNum = getCanMovePositionNum(xTemp, yTemp);

if (canMovePoisitionNum != 0)

poisition.push_back(Position(xTemp, yTemp, canMovePoisitionNum));

}

sort(poisition.begin(), poisition.end(), cmp);

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;

bool visited[8][8];
bool success = false;
int roate[64];

struct Position{
    Position(int x_ = 0, int y_ = 0, int num = 0): x(x_), y(y_), canMovePoisitionNum(num) { }
    int x;
    int y;
    int canMovePoisitionNum;
};

Position Move[8] = {Position(1, -2), Position(2, -1), Position(2, 1), Position(1, 2),
                    Position(-1, 2), Position(-2, 1), Position(-2, -1), Position(-1, -2)};

bool isValid(int x, int y) {
    return x >= 0 && y >= 0 && x <= 7 && y <= 7;
}

int getCanMovePositionNum(int x, int y) {
    int canMovePoisitionNum = 0;
    for (int i = 0; i != 8; ++i) {
        if(isValid(x + Move[i].x, y + Move[i].y))
            canMovePoisitionNum++;
    }
    return canMovePoisitionNum;
}

bool cmp(const Position &a, const Position &b) {
    return a.canMovePoisitionNum < b.canMovePoisitionNum;
}

void search(int step, int x, int y) {
    vector<Position> poisition;
    for (int i = 0; i != 8; ++i) {
        int xTemp = x + Move[i].x;
        int yTemp = y + Move[i].y;
        if (isValid(xTemp, yTemp)) {
            int canMovePoisitionNum = getCanMovePositionNum(xTemp, yTemp);
            if (canMovePoisitionNum != 0)
                poisition.push_back(Position(xTemp, yTemp, canMovePoisitionNum));
        }
    }
    sort(poisition.begin(), poisition.end(), cmp);
    for (int i = 0; i != poisition.size(); ++i) {
        if (success)
            return;
        if (step == 63) {
            success = true;
            return;
        }
        if (!visited[poisition[i].x][poisition[i].y]) {
            ++step;
            roate[step] = 8 * poisition[i].x + poisition[i].y + 1;
            visited[poisition[i].x][poisition[i].y] = true;
            search(step, poisition[i].x, poisition[i].y);
            visited[poisition[i].x][poisition[i].y] = false;
            --step;
        }
    }
}

int main(int argc, char *argv[])
{
    int N, x, y;
    while (scanf("%d", &N) && N != -1) {
        roate[0] = N;
        memset(visited, false, sizeof(visited));
        success = false;
        x = (N - 1) / 8;
        y = (N - 1) % 8;

        visited[x][y] = true;
        search(0, x, y);

        for (int i = 0; i != 63; i++)
            printf("%d ", roate[i]);
        printf("%d\n", roate[63]);
    }

    return 0;
}
时间: 2024-11-07 23:35:41

sicily 1153. 马的周游问题的相关文章

Sicily 1153. 马的周游问题 解题报告

1153_马的周游问题 题目链接: http://soj.me/1153 题目大意: 给定一个8×8棋盘,格子标号1到64,输入一个初始位置的标号,按照马走“日”字的方法,找一条能刚好走完整个棋盘的路径,每个格子恰好只访问过一次. 思路: 用深度优先搜索的方法可以解决问题.首先用二维数组表示整个棋盘,直接用bool类型来表示棋盘的格子是否被访问过.由于输入的是格子的标号,要方便搜索这里用了Point类来表示格子,将序号转化为Point类型.成员ourDegree表示一个点的出度,即这个点可以访问

Sicily 1153: 马的周游问题(DFS+剪枝)

这道题没有找到一条回路,所以不能跟1152一样用数组储存后输出.我采用的方法是DFS加剪枝,直接DFS搜索会超时,优化的方法是在搜索是优先走出度小的路径,比如move1和move2都可以走,但是如走了move1后下一步有7种方向可以走,而走了move2后有2种方向可以走,那我们就优先走move2,具体实现参考代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 int _move[8][2] ={{1, -2}, {2, -1}, {2,

Sicily Online Judge 1153.马的周游问题

1153. 马的周游问题 Constraints Time Limit: 1 secs, Memory Limit: 32 MB , Special Judge Description 和题目C同样的任务,这里只是把棋盘扩大到标准的国际象棋.对这样一个8 * 8的棋盘用同样的方法编号如下: 1     2     3       4     5     6       7     8 9     10       11    12       13    14       15    16 17

编程题目分类(剪辑)

1. 编程入门 2. 数据结构 3. 字符串 4. 排序 5. 图遍历 6. 图算法 7. 搜索:剪枝,启发式搜索 8. 动态规划/递推 9. 分治/递归 10. 贪心 11. 模拟 12. 算术与代数 13. 组合问题 14. 数论 15. 网格,几何,计算几何 [编程入门] PC 110101, uva 100, The 3n+1 problem, 难度 1 PC 110102, uva 10189, Minesweeper, 难度 1 PC 110103, uva 10137, The T

sicily 1152 简单马周游 深度优先搜索及回溯算法

1152. 简单的马周游问题 Constraints Time Limit: 1 secs, Memory Limit: 32 MB , Special Judge Description 在一个5 * 6的棋盘中的某个位置有一只马,如果它走29步正好经过除起点外的其他位置各一次,这样一种走法则称马的周游路线,试设计一个算法,从给定的起点出发,找出它的一条周游路线. 为了便于表示一个棋盘,我们按照从上到下,从左到右对棋盘的方格编号,如下所示: 1     2     3       4    

(转)sicily题目分类

Sicily题目分类 ·         [数据结构/图论] 1310 Right-Heavy Tree   笛卡尔树相关,复杂度O(N)或O(NlogN). ·1426 Phone List         电话号码前缀检索,trie树相关. ·1443 Printer Queue      基本队列操作. ·1149 等价表达式         判断表达式是否等价(递归求解) ·1136 山海经             n长序列里求m次区间询问的最大连续子区间和.线段树/RMQ ·1252

Sicily-1153 解题报告

一.原题中文大意. 1      2       3      4       5      6         7     8 9     10       11    12      13     14       15    16 17    18      19    20       21    22       23    24 25    26      27    28       29    30       31    32 33    34      35    36   

大数据揭秘: 原来单身女生有这些特点...,掌握大数据,你远远不止会这些

据媒体报道,中国目前的单身成年女性的数量已经超过一个多亿,也就是说14.3%的成年女性处于单身状态,与日本全国人口总数基本相当. 知己知彼,百战不殆.如果你是一个单身女性,你可以看到自己的某些影子:如果是单身男生,你需要了解目标人群的特点:如果是已婚男士,要相信"天下凤凰一般美!!!" 说 明 开始本文之前有几点说明: 1.本文数据主要来自于某婚恋网站的爬虫搜索数据: 2.该网站上的女生默认为单身: 3.该网站上的个人信息默认为真实: 4.爬取的样本数据具有充分的代表性. 5.很多初学

中国历史十大经典战役

中国历史十大经典战役  NO.1 牧野之战 "牧野洋洋,--时维鹰扬,凉彼武王肆伐大商,会期清明"现代人根据史书记载的天象,甚至推算出了具体时间是公元前1106年2月4日.周武王统率兵车300乘,虎贲3000人,甲士4万5千人,汇集各部落的兵力,大破商军的共约17万人于牧野. NO.2 城濮之战 面对锋芒必露的楚军,晋文公选择"退避三舍",然后集中优势兵力对于楚军3路兵马实行各个击破,最后战斗以晋文公在践土朝觐周王,会盟诸侯结束. NO.3 长平之战 秦赵为了上党的