《编程思维与实践》1092.显示路径
题目
思路
注意到 x + y = ± 2 0 ± 2 1 . . . ± 2 n x+y=±2^0±2^1...±2^n x+y=±20±21...±2n为奇数,所以一个点能到达的必要条件为|x|+|y|是奇数.
特别地,我们称|x|+|y|为一个点和原点间的曼哈顿距离.
观察到:
①走一步时有 ∣ x ∣ + ∣ y ∣ = 1 ∈ ( 0 , 2 1 ] |x|+|y|=1\in(0,2^1] ∣x∣+∣y∣=1∈(0,21] ;
②走两步时有 ∣ x ∣ + ∣ y ∣ ∈ ( 0 , 2 2 ] , 可能取值为 1 和 3 , 其中新增的 3 ∈ ( 2 1 , 2 2 ] |x|+|y|\in(0,2^2],可能取值为1和3,其中新增的3\in(2^1,2^2] ∣x∣+∣y∣∈(0,22],可能取值为1和3,其中新增的3∈(21,22] ;
③走三步时有 ∣ x ∣ + ∣ y ∣ ∈ ( 0 , 2 3 ] , 可能取值为 1 , 3 , 5 和 7 , 其中新增的 5 和 7 ∈ ( 2 2 , 2 3 ] |x|+|y|\in(0,2^3],可能取值为1,3,5和7,其中新增的5和7\in(2^2,2^3] ∣x∣+∣y∣∈(0,23],可能取值为1,3,5和7,其中新增的5和7∈(22,23] ;
④走四步时有 ∣ x ∣ + ∣ y ∣ ∈ ( 0 , 2 4 ] , 可能取值为 1 , 3 , 5 , 7 , 9 , 11 , 13 和 15 , 其中新增的 9 , 11 , 13 和 15 ∈ ( 2 3 , 2 4 ] |x|+|y|\in(0,2^4],可能取值为1,3,5,7,9,11,13和15,其中新增的9,11,13和15\in(2^3,2^4] ∣x∣+∣y∣∈(0,24],可能取值为1,3,5,7,9,11,13和15,其中新增的9,11,13和15∈(23,24] .
初步猜测|x|+|y|是奇数也是该点能到达的充分条件.
下面给出更强的结论和证明:
结论 : ∣ x ∣ + ∣ y ∣ 为奇数且满足 2 k − 1 − 1 < ∣ x ∣ + ∣ y ∣ ≤ 2 k − 1 , 则该点可到达 , 且所需的最少步数为 k . 证明 : 设点 ( ∣ x ∣ , ∣ y ∣ ) 可以到达 , 则由必要性知 ∣ x ∣ + ∣ y ∣ 为奇数 , 当走 k 步到达时满足 0 < ∣ x ∣ + ∣ y ∣ ≤ 2 0 + 2 1 + . . . + 2 k − 1 = 2 k − 1 , 当走 k − 1 步到达时满足 0 < ∣ x ∣ + ∣ y ∣ ≤ 2 k − 1 − 1 , 所以当可到达的点对应的 ∣ x ∣ + ∣ y ∣ 落在 ( 2 k − 1 − 1 , 2 k − 1 ] 中时 , 至少需要走 k 步 , 下面证明走 k 步时可以到达 ( 0 , 2 k − 1 ] 中的所有奇数值 : 当步数为 1 时可以可以到达点 ( 0 , 1 ) , 对应的 ∣ x ∣ + ∣ y ∣ = 1 落在 ( 0 , 1 ] 中 , 满足要求 ; 下设步数小于 k 时结论成立 , 证明步数为 k 的情形 : 由归纳假设 , 走 k − 1 步可到达的点满足 ∣ x ∣ + ∣ y ∣ 均落在 ( 0 , 2 k − 1 − 1 ] 的奇数值中 , 不妨设 y = 0 , 则 ∣ x ∣ = 1 , 3 , 5... 2 k − 1 − 1 , 再走一步 , 则 : ∣ x − 2 k − 1 ∣ = 1 , 3 , 5... 2 k − 1 − 1 , 2 k − 1 + 1 , 2 k − 1 + 3... 2 k − 1 所以走 k 步时可以到达 ( 0 , 2 k − 1 ] 中的所有奇数值 , 那么由前面的论述可知可到达的点对应的 ∣ x ∣ + ∣ y ∣ 落在 ( 2 k − 1 − 1 , 2 k − 1 ] 中时所需的最少步数即为 k 步 . 结论:\,|x|+|y|为奇数且满足\, 2^{k-1}-1<|x|+|y|≤2^k-1,则该点可到达,且所需的最少步数为k.\\ 证明:设点(|x|,|y|)可以到达,则由必要性知|x|+|y|为奇数,\\ 当走k步到达时满足0<|x|+|y|≤2^0+2^1+...+2^{k-1}=2^k-1,\\ 当走k-1步到达时满足0<|x|+|y|≤2^{k-1}-1,\\ 所以当可到达的点对应的|x|+|y|落在(2^{k-1}-1,2^k-1]中时,至少需要走k步,\\ 下面证明走k步时可以到达(0,2^k-1]中的所有奇数值:\\ 当步数为1时可以可以到达点(0,1),对应的|x|+|y|=1落在(0,1]中,满足要求;\\ 下设步数小于k时结论成立,证明步数为k的情形:\\ 由归纳假设,走k-1步可到达的点满足|x|+|y|均落在(0,2^{k-1}-1]的奇数值中,\\ 不妨设y=0,则|x|=1,3,5...2^{k-1}-1,再走一步,则:\\ |x-2^{k-1}|=1,3,5...2^{k-1}-1,2^{k-1}+1,2^{k-1}+3...2^{k}-1 \\ 所以走k步时可以到达(0,2^k-1]中的所有奇数值,\\ 那么由前面的论述可知可到达的点对应的|x|+|y|落在(2^{k-1}-1,2^k-1]中时所需的最少步数即为k步. 结论:∣x∣+∣y∣为奇数且满足2k−1−1<∣x∣+∣y∣≤2k−1,则该点可到达,且所需的最少步数为k.证明:设点(∣x∣,∣y∣)可以到达,则由必要性知∣x∣+∣y∣为奇数,当走k步到达时满足0<∣x∣+∣y∣≤20+21+...+2k−1=2k−1,当走k−1步到达时满足0<∣x∣+∣y∣≤2k−1−1,所以当可到达的点对应的∣x∣+∣y∣落在(2k−1−1,2k−1]中时,至少需要走k步,下面证明走k步时可以到达(0,2k−1]中的所有奇数值:当步数为1时可以可以到达点(0,1),对应的∣x∣+∣y∣=1落在(0,1]中,满足要求;下设步数小于k时结论成立,证明步数为k的情形:由归纳假设,走k−1步可到达的点满足∣x∣+∣y∣均落在(0,2k−1−1]的奇数值中,不妨设y=0,则∣x∣=1,3,5...2k−1−1,再走一步,则:∣x−2k−1∣=1,3,5...2k−1−1,2k−1+1,2k−1+3...2k−1所以走k步时可以到达(0,2k−1]中的所有奇数值,那么由前面的论述可知可到达的点对应的∣x∣+∣y∣落在(2k−1−1,2k−1]中时所需的最少步数即为k步. {}}
剩下需要解决的问题变为如何走使步数最少且能到达终点?逆向考虑:从终点往原点走,则只需要使每步走完后的曼哈顿距离比之前小即可(越来越靠近原点).
判断依据: |x|和|y|的大小 , 大的先变可以让整体更加接近原点.
如下图所示:
注意的点:
1.如果终点为原点直接输出0.
2.路径可以开一个数组记录,也可以等递归调用结束后直接输出.
代码
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void Path(long long x,long long y,int k)
{
if(k)
{
long long d=((long long)1)<<(k-1); //2^{k-1} 第k步走的距离
if(llabs(x)>llabs(y)) //x和y不可能相等 不然和为偶数
{
if(x>0) //左走
{
Path(x-d,y,k-1); //递归调用后输出
printf("E"); //倒着向左=正着向右
}
else
{
Path(x+d,y,k-1);
printf("W");
}
}
else
{
if(y>0)
{
Path(x,y-d,k-1);
printf("N");
}
else
{
Path(x,y+d,k-1);
printf("S");
}
}
}
}
int main()
{
long long x,y;
scanf("%lld%lld",&x,&y);
if(x==0&&y==0) //
{
printf("0\n");
}
else
{
long long temp=(x>0?x:-x)+(y>0?y:-y); //绝对值相加
if(temp%2==0)
{
printf("-1\n");
}
else
{
long long judge=1;
int k=0;
while(judge<temp+1)
{
judge*=2;
k++; //最少步数
}
printf("%d\n",k);
Path(x,y,k);
}
}
return 0;
}