58-最小步数

最少步数

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 4
描述

这有一个迷宫,有0~8行和0~8列:

 1,1,1,1,1,1,1,1,1
 1,0,0,1,0,0,1,0,1
 1,0,0,1,1,0,0,0,1
 1,0,1,0,1,1,0,1,1
 1,0,0,0,0,1,0,0,1
 1,1,0,1,0,1,0,0,1
 1,1,0,1,0,1,0,0,1
 1,1,0,1,0,0,0,0,1
 1,1,1,1,1,1,1,1,1

0表示道路,1表示墙。

现在输入一个道路的坐标作为起点,再如输入一个道路的坐标作为终点,问最少走几步才能从起点到达终点?

(注:一步是指从一坐标点走到其上下左右相邻坐标点,如:从(3,1)到(4,1)。)

输入
第一行输入一个整数n(0<n<=100),表示有n组测试数据;
随后n行,每行有四个整数a,b,c,d(0<=a,b,c,d<=8)分别表示起点的行、列,终点的行、列。
输出
输出最少走几步。
样例输入
2
3 1  5 7
3 1  6 7
样例输出
12
11
来源
[苗栋栋]原创
上传者

苗栋栋





#include<iostream>
using namespace std;
int minsteps=100;
int maze[9][9]={{1,1,1,1,1,1,1,1,1},
                {1,0,0,1,0,0,1,0,1},
                {1,0,0,1,1,0,0,0,1},
                {1,0,1,0,1,1,0,1,1},
                {1,0,0,0,0,1,0,0,1},
                {1,1,0,1,0,1,0,0,1},
                {1,1,0,1,0,1,0,0,1},
                {1,1,0,1,0,0,0,0,1},
                {1,1,1,1,1,1,1,1,1}, 
};
int min(int a,int b)
{
return a<b?a:b;

void visit(int i,int j,int endI,int endJ,int step)
{

    maze[i][j]=2;
if(i==endI&&j==endJ)    
    minsteps=min(minsteps,step);
     
if(maze[i][j+1]==0) visit(i,j+1,endI,endJ,step+1);//走一步就+1 
if(maze[i][j-1]==0) visit(i,j-1,endI,endJ,step+1);
if(maze[i+1][j]==0) visit(i+1,j,endI,endJ,step+1);
if(maze[i-1][j]==0) visit(i-1,j,endI,endJ,step+1);
maze[i][j]=0;
step--; //不符合条件就-1 
}


int main()
{
int startI,startJ,endI,endJ;
int n,a,b,c,d;

cin>>n;
while(n--)
{
int count[1000],i,j,step=0;
cin>>a>>b>>c>>d;
startI=a,startJ=b,endI=c,endJ=d;
visit(a,b,c,d,step); 
cout<<minsteps<<endl;
minsteps=999; //这步很关键,因为minsteps是全局变量,值会保留,所以每次都要修改。

}
return 0;

<think>我们正在讨论数字黑洞,特别是卡普雷卡尔黑洞(也称为重排求差黑洞)。根据引用[2],它描述了如下过程: 对于任意一个四位数(至少有两个不同的数字),将它的各位数字重新排列,得到最大数和最小数,然后相减得到新的数。重复此过程,最终会收敛到6174这个数,6174被称为卡普雷卡尔常数。 例如,以2025为例: 1. 重排得到最大数:5220,最小数:0225(即225),相减:5220-225=4995 2. 4995:重排最大数:9954,最小数:4599,相减:9954-4599=5355 3. 5355:重排最大数:5553,最小数:3555,相减:5553-3555=1998 4. 1998:重排最大数:9981,最小数:1899,相减:9981-1899=8082 5. 8082:重排最大数:8820,最小数:0288(即288),相减:8820-288=8532 6. 8532:重排最大数:8532,最小数:2358,相减:8532-2358=6174 7. 6174:重排最大数:7641,最小数:1467,相减:7641-1467=6174 因此,2025经过7步到达6174,并停留在6174。 数学上,这个黑洞现象只存在于四位数吗?实际上,对于其他位数的数字,可能有不同的黑洞或循环。例如: - 三位数:黑洞是495(如:954-459=495,然后重复得到495)。 - 两位数:会进入一个循环(9的倍数),例如:63-36=27,72-27=45,54-45=9,90-9=81,81-18=63,进入循环。 - 五位数:可能会进入不同的循环,没有单一的黑洞。 算法实现: 我们可以编写一个函数,接受一个数字(作为字符串或整数),然后重复进行重排求差操作,直到出现循环或达到某个固定点。 步骤: 1. 将数字转换为字符串,并补零使其达到指定位数(例如四位数就补到4位)。 2. 将数字的各位拆开,排序(升序和降序)得到最小数和最大数。 3. 计算差值,并作为新的数字。 4. 重复直到出现重复的数字(即循环)或达到黑洞。 注意:如果数字各位都相同(如1111),则下一步为0,但0重复操作会得到0。但通常我们要求数字至少有两个不同的数字。 下面我们用Python实现一个计算卡普雷卡尔黑洞过程的函数,并演示一个例子。 ```python def kaprekar_blackhole(n, digits=4): """ 计算卡普雷卡尔黑洞过程 :param n: 起始数字,整数 :param digits: 数字的位数,默认为4 :return: 每一步的结果列表,直到出现重复或达到0 """ seen = [] # 记录已经出现过的数字,用于检测循环 current = n # 如果当前数字未出现过,且不是0,则继续 while current not in seen and current != 0: seen.append(current) # 将数字转为字符串,前面补零使其达到指定位数 s = str(current).zfill(digits) # 如果数字位数超过指定位数,则截取后digits位(但通常我们要求指定位数,所以补零后就是digits位) # 拆分成各位数字,排序 digits_list = sorted(s) # 升序排列 min_str = ''.join(digits_list) # 最小数 max_str = ''.join(digits_list[::-1]) # 最大数 min_num = int(min_str) max_num = int(max_str) current = max_num - min_num # 如果当前数字已经出现过,则跳出循环(避免无限循环) if current in seen: break return seen # 测试2025 steps = kaprekar_blackhole(2025) print("步骤:") for i, num in enumerate(steps): print(f"步骤{i+1}: {num}") print(f"最终到达: {steps[-1]}") ``` 但是,上面的函数在遇到6174时会停止,因为6174会重复出现(下一步还是6174),所以我们在循环中遇到重复就停止。注意,我们一开始将当前数字加入seen,然后计算下一步,如果下一步在seen中,则停止。这样,最后一步就是黑洞数字(如6174)或者循环开始的数字。 然而,上面的函数在遇到0时也会停止,比如输入为1111,则: 第一步:1111 -> 1111-1111=0,然后停止,返回[1111,0]?但注意,我们在循环条件中遇到0就停止,所以不会将0加入seen两次。但实际我们希望记录0。 修改:我们先将当前数字加入seen,然后计算下一个数字,如果下一个数字已经在seen中或者为0,则停止。但0的情况:如果当前是0,那么下一步还是0,所以我们应该在得到0时停止,因为0会一直重复。 但是,对于黑洞6174,我们得到6174后,下一步计算还是6174,所以会出现在seen中(因为seen中已经有6174),所以停止。 因此,函数可以工作。 但是,注意:我们要求输入的数字是整数,并且位数不超过digits(或者我们可以处理任意位数,但补零到digits位)。对于不足digits位的数字,我们补零。例如,输入1,四位数则视为0001,然后重排:1000和0001,相减:1000-1=999,然后继续。 然而,对于非四位数的黑洞,我们可以通过改变digits参数来研究。 例如,三位数的黑洞495: ```python steps = kaprekar_blackhole(123, digits=3) print(steps) # 应该会到达495 ``` 但是,注意:有些数字可能不会收敛到黑洞,而是进入循环(比如两位数),所以我们的函数会记录所有步骤直到出现重复。 现在,我们回到用户的问题:用户询问数字黑洞的数学概念和算法实现。 数学概念: 数字黑洞是指一种数学运算过程,无论从哪个数字开始,最终都会陷入一个特定的数字或循环。卡普雷卡尔黑洞是其中一种,通过重排数字求差,最终得到6174(四位数)或495(三位数)等。 算法实现如上所示。 此外,还有其他数字黑洞,比如“123黑洞”(数位平方和)等。 下面我们生成相关问题。</think>### 数字黑洞的数学概念与算法实现 #### **数学概念** 数字黑洞是一种数学现象,指特定运算规则下,数字序列最终会陷入固定数值或循环。最常见的两种类型: 1. **卡普雷卡尔黑洞(重排求差黑洞)** - 针对四位数:将数字各位**重排**组成最大数 $M$ 和最小数 $m$,计算差值 $M - m$,重复此过程必收敛到 $6174$(卡普雷卡尔常数)[^1]。 $$M = \text{digits descending}, \quad m = \text{ascending}, \quad \Delta = M - m$$ - 数学特性:6174 是唯一不动点,满足 $7641 - 1467 = 6174$[^2]。 2. **其他黑洞类型** - **三位数黑洞**:收敛到 $495$(如 $954 - 459 = 495$)。 - **平方和黑洞**:各位平方和重复计算,最终陷入 $1$ 或循环 $4 \to 16 \to 37 \to 58 \to 89 \to 145 \to 42 \to 20 \to 4$。 #### **算法实现(Python)** 以卡普雷卡尔黑洞为例,实现步骤如下: ```python def kaprekar_blackhole(n: int, max_iter=20): """ 计算数字黑洞过程 :param n: 起始四位数(需至少含两个不同数字) :param max_iter: 最大迭代次数 :return: 每一步计算结果列表 """ sequence = [] for _ in range(max_iter): # 将数字转为4位字符串(补零) s = str(n).zfill(4) # 重排求最大和最小值 max_num = int(''.join(sorted(s, reverse=True))) min_num = int(''.join(sorted(s))) # 计算差值 n = max_num - min_num sequence.append(n) # 检测循环或不动点 if n == 0 or n == 6174: break return sequence # 示例:2025的黑洞过程 print(kaprekar_blackhole(2025)) # 输出: [4995, 5355, 1998, 8082, 8532, 6174] ``` **关键步骤说明**: 1. **数字格式化**:用 `zfill(4)` 补零保证四位数(如 `5` → `"0005"`)。 2. **重排求极值**: - 升序排列得最小数(`"0255"` → `0255 = 255`) - 降序排列得最大数(`"5520"`) 3. **终止条件**: - 达到不动点 $6174$ - 或陷入 $0$(如输入 $1111$) #### **数学验证** 对任意四位数 $a b c d$($a \geq b \geq c \geq d$),差值通式为: $$ \Delta = (1000a + 100b + 10c + d) - (1000d + 100c + 10b + a) = 999(a-d) + 90(b-c) $$ 该运算具有压缩性,经有限步必收敛[^1]。 --- ### **相关问题** 1. 除四位数外,其他位数的数字是否存在卡普雷卡尔黑洞? 2. 如何证明6174是四位数重排求差的唯一不动点? 3. 数字黑洞现象在密码学或数据加密中有哪些潜在应用? [^1]: 探索数字黑洞:一个迷人的算法挑战。项目技术分析。 [^2]: 用python实现卡普雷卡尔黑洞的计算。卡普雷卡尔黑洞描述。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值