UVa 439/HDU 1372/POJ 2243/ZOJ 1091 Knight Moves(BFS纯数学方法)

2024-03-05 21:08

本文主要是介绍UVa 439/HDU 1372/POJ 2243/ZOJ 1091 Knight Moves(BFS纯数学方法),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

439 - Knight Moves

Time limit: 3.000 seconds

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=105&page=show_problem&problem=380

http://acm.hdu.edu.cn/showproblem.php?pid=1372

http://poj.org/problem?id=2243

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1091

A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.

Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part.

Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.

Input Specification

The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.

Output Specification

For each test case, print one line saying "To get from xx to yy takes n knight moves.".

Sample Input

e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6

Sample Output

To get from e2 to e4 takes 2 knight moves.
To get from a1 to b2 takes 4 knight moves.
To get from b2 to c3 takes 2 knight moves.
To get from a1 to h8 takes 6 knight moves.
To get from a1 to h7 takes 5 knight moves.
To get from h8 to a1 takes 6 knight moves.
To get from b1 to c3 takes 1 knight moves.
To get from f6 to f6 takes 0 knight moves.

题意:

在辽阔的N*N大草原上(棋盘)上你有一只草泥马,马走日。求从a到b怎么走步数最小。


思路:

1. BFS,复杂度O(N^2),N指棋盘边长。

2. 数学方法,复杂度O(N^2),但系数比第一种小很多:

设横纵坐标的差值分别是x,y。由于我们的草泥马只能有8种走法,实际上只会出现4种(方向向量有(1,2),(2,1),(1,-2),(2,-1),(-1,2),(-2,1),(-1,-2),(-2,-1)8种,但是如果要走最小的次数,就不可能同时出现(1,2)和(-1,-2)这样相反的方向向量,所以只会出现4种)。所以,我们设方向向量为(1,2),(2,1),(2,-1),(1,-2)的有a,b,c,d次,其中a,b,c,d可以为负数(比如a为负数代表方向向量为(-1,-2))。

于是,可以列两个方程:


我们要求的是|a|+|b|+|c|+|d|的最小值。把a,b,看做常量,解得:


所以a+2b≡2x+y(mod 3),即a≡-2b+2x+y(mod 3)(-3≤a,b3)

但由于a,b关系的制约,当b在-3到3范围内变动时,a只有三种情况(取-3,0,3或-2,1或-1,2)

所以a,b的组合有16或17种,比较每种情况的|a|+|b|+|c|+|d|,求最小的即可。

但是在计算角落时要另外考虑,比如(a1,b2)按上面方法算的是2,实际是4。

经过计算知,对于8*8的只有4种情况:(a1,b2),(a8,b7),(g2,h1),(g7,h8),

对这四种情况单独拿出来说就好了。


完整代码:

BFS,很慢。

/*UVaOJ: 0.022s*/
/*HDU: 31ms,244KB*/
/*POJ: 266ms,156KB*/
/*ZOJ: 10ms,180KB*/#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;bool vis[9][9];
int a, b, c, d;
int mov[8][2] = {1, 2, -1, 2, -2, 1, -2, -1, -1, -2, 1, -2, 2, -1, 2, 1};struct node
{int x, y, step;
} lnode;int bfs()
{int i;queue<node>q;node cur, next;cur.x = a;cur.y = b;cur.step = 0;vis[cur.x][cur.y] = true;q.push(cur);while (!q.empty()){cur = q.front();q.pop();for (i = 0; i < 8; i++){next.x = cur.x + mov[i][0];next.y = cur.y + mov[i][1];if (next.x >= 1 && next.x <= 8 && next.y >= 1 && next.y <= 8){if (next.x == c && next.y == d){next.step = cur.step + 1;return next.step;}if (!vis[next.x][next.y]){next.step = cur.step + 1;vis[next.x][next.y] = true;q.push(next);}}}}return -1;
}int main()
{char str[5], str2[5];while (~scanf("%s %s", str, str2)){memset(vis, 0, sizeof(vis));a = str[0] - '`' ;//'a'前面是'`'b = str[1] - '0';c = str2[0] - '`' ;d = str2[1] - '0';int ans = 0;if (a != c || b != d)ans = bfs();printf("To get from %s to %s takes %d knight moves.\n", str, str2, ans);}return 0;
}


数学方法,较快。

/*UVaOJ: 0.019s*/
/*HDU: 15ms,232KB*/
/*POJ: 16ms,144KB*/
/*ZOJ: 0ms,180KB*/#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;int main()
{char except[8][3] = {"a1", "b2", "a8", "b7", "g2", "h1", "g7", "h8"};char s1[5], s2[5];int  x, y, a, b, c, d,sum, m, temp;while (~scanf("%s%s", s1, s2)){if (!strcmp(s1, s2)){printf("To get from %s to %s takes 0 knight moves.\n", s1, s2);continue;}bool flag = false;for (int i = 0; i < 8; i += 2)if (!((strcmp(s1, except[i]) || strcmp(s2, except[i + 1]))&& (strcmp(s1, except[i + 1]) || strcmp(s2, except[i])))){flag = true;break;}if (flag){printf("To get from %s to %s takes 4 knight moves.\n", s1, s2);continue;}x = s2[0] - s1[0];y = s2[1] - s1[1];sum = 1 << 6;//下面a,b的取值范围是由-3<=a,b<=3所确定的//注意b取负数和正数的情况是不一样的//注意取模时,-1%3!=2而是=-1for (b = -3; b <= 3; b++){m = (y + 2 * x - 2 * b) % 3;for (a = m - 3; a <= m + 3; a += 3){c = (2 * x + y - 4 * a - 5 * b) / 3;d = (5 * a + 4 * b - x - 2 * y) / 3;temp = abs(a) + abs(b) + abs(c) + abs(d);if (temp < sum)sum = temp;}}printf("To get from %s to %s takes %d knight moves.\n", s1, s2, sum);}return 0;
}


题外话:可以打表。

这篇关于UVa 439/HDU 1372/POJ 2243/ZOJ 1091 Knight Moves(BFS纯数学方法)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/777809

相关文章

MySQL启动报错:InnoDB表空间丢失问题及解决方法

《MySQL启动报错:InnoDB表空间丢失问题及解决方法》在启动MySQL时,遇到了InnoDB:Tablespace5975wasnotfound,该错误表明MySQL在启动过程中无法找到指定的s... 目录mysql 启动报错:InnoDB 表空间丢失问题及解决方法错误分析解决方案1. 启用 inno

Python函数返回多个值的多种方法小结

《Python函数返回多个值的多种方法小结》在Python中,函数通常用于封装一段代码,使其可以重复调用,有时,我们希望一个函数能够返回多个值,Python提供了几种不同的方法来实现这一点,需要的朋友... 目录一、使用元组(Tuple):二、使用列表(list)三、使用字典(Dictionary)四、 使

Linux查看系统盘和SSD盘的容量、型号及挂载信息的方法

《Linux查看系统盘和SSD盘的容量、型号及挂载信息的方法》在Linux系统中,管理磁盘设备和分区是日常运维工作的重要部分,而lsblk命令是一个强大的工具,它用于列出系统中的块设备(blockde... 目录1. 查看所有磁盘的物理信息方法 1:使用 lsblk(推荐)方法 2:使用 fdisk -l(

使用Python获取JS加载的数据的多种实现方法

《使用Python获取JS加载的数据的多种实现方法》在当今的互联网时代,网页数据的动态加载已经成为一种常见的技术手段,许多现代网站通过JavaScript(JS)动态加载内容,这使得传统的静态网页爬取... 目录引言一、动态 网页与js加载数据的原理二、python爬取JS加载数据的方法(一)分析网络请求1

MySQL查看表的最后一个ID的常见方法

《MySQL查看表的最后一个ID的常见方法》在使用MySQL数据库时,我们经常会遇到需要查看表中最后一个id值的场景,无论是为了调试、数据分析还是其他用途,了解如何快速获取最后一个id都是非常实用的技... 目录背景介绍方法一:使用MAX()函数示例代码解释适用场景方法二:按id降序排序并取第一条示例代码解

Python中合并列表(list)的六种方法小结

《Python中合并列表(list)的六种方法小结》本文主要介绍了Python中合并列表(list)的六种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录一、直接用 + 合并列表二、用 extend() js方法三、用 zip() 函数交叉合并四、用

Java 中的跨域问题解决方法

《Java中的跨域问题解决方法》跨域问题本质上是浏览器的一种安全机制,与Java本身无关,但Java后端开发者需要理解其来源以便正确解决,下面给大家介绍Java中的跨域问题解决方法,感兴趣的朋友一起... 目录1、Java 中跨域问题的来源1.1. 浏览器同源策略(Same-Origin Policy)1.

Java Stream.reduce()方法操作实际案例讲解

《JavaStream.reduce()方法操作实际案例讲解》reduce是JavaStreamAPI中的一个核心操作,用于将流中的元素组合起来产生单个结果,:本文主要介绍JavaStream.... 目录一、reduce的基本概念1. 什么是reduce操作2. reduce方法的三种形式二、reduce

MybatisX快速生成增删改查的方法示例

《MybatisX快速生成增删改查的方法示例》MybatisX是基于IDEA的MyBatis/MyBatis-Plus开发插件,本文主要介绍了MybatisX快速生成增删改查的方法示例,文中通过示例代... 目录1 安装2 基本功能2.1 XML跳转2.2 代码生成2.2.1 生成.xml中的sql语句头2

python3 pip终端出现错误解决的方法详解

《python3pip终端出现错误解决的方法详解》这篇文章主要为大家详细介绍了python3pip如果在终端出现错误该如何解决,文中的示例方法讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下... 目录前言一、查看是否已安装pip二、查看是否添加至环境变量1.查看环境变量是http://www.cppcns