X星球居民小区的楼房全是一样的,并且按矩阵样式排列。其楼房的编号为1,2,3...
当排满一行时,从下一行相邻的楼往反方向排号。
比如:当小区排号宽度为6时,开始情形如下:
1 2 3 4 5 6
12 11 10 9 8 7
13 14 15 .....
我们的问题是:已知了两个楼号m和n,需要求出它们之间的最短移动距离(不能斜线方向移动)
输入为3个整数w m n,空格分开,都在1到10000范围内
w为排号宽度,m,n为待计算的楼号。
要求输出一个整数,表示m n 两楼间最短移动距离。
例如:
用户输入:
6 8 2
则,程序应该输出:
4
再例如:
用户输入:
4 7 20
则,程序应该输出:
5
国际惯例,分析案例理解题意
思路:这道题思路比较容易想到,就是求两个房子间的行号和列号分别作差,再相加,就是题目所求的答案。 如何求出行号和列号呢?那就要根据宽度和题目所给的条件来找出关系式。这里有个特殊的规则就是,每间隔一行,房子就要往反方向排号。
默认行号和列号从1开始,x代表房号。
对于行号:如果 x < w 肯定在第一行
否则 我们通过x / w+1可以求得
但有个特殊情况,如果x%w==0说明它是这行中最大的数,也就是w的倍数,那么做除法它可以得到进位,因此不用+1
int row(int x){//行号
if(x<=w) return 1;
return x%w==0?x/w:(x/w)+1;
}
对于列号:如果x<w 那么x就在它楼号所在的列
列的情况会相对比较复杂,因为有每隔一行就往反方向排号。
所以要分类讨论,分为偶数行和奇数行
由于我们从第一行开始算,所以就是奇数行正常排列,偶数行按反方向排列
① | ② | ③ | ④ | ⑤ | ⑥ | |
---|---|---|---|---|---|---|
① | 1 | 2 | 3 | 4 | 5 | 6 |
② | 12 | 11 | 10 | 9 | 8 | 7 |
③ | 13 | 14 | 15 | 16 | 17 | 18 |
④ | 24 | 23 | 22 | 21 | 20 | 19 |
当w=6时
奇数行中的14和18
对于楼号14 :(14%6=2)楼号14的确在第2列
对于楼号18:(18%6=0)这时可以观察到它的列号就是w = 6
因此对于模等于0的情况直接赋值为w
偶数行中的12和8
对于楼号12:(12%6=0)楼号其实就在第1列
可以观察到偶数行模0的楼号都是第1列,直接赋值为1
对于楼号8:此时8并不在一个正序的序列中,那就找出规律,比如(8%6=2)但其实它在倒数第2位,所以我们找出一个式子可以满足这个关系(w-(x%w))+1
int col(int x){//列号
if(x<=w) return x;
if(row(x)%2==1){ //奇数行
return x%w==0?w:x%w;
}else{ //偶数行
return x%w==0?1:(w-(x%w))+1;
}
}
总结:这种题不难,但需要耐心的找规律。多演算,还有注意找一些特殊的位置,比如边缘位置,看是否满足普遍规律,不满足就单独处理它。
全部代码如下:
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int w,m,n;
int row(int x){//行号
if(x<=w) return 1;
return x%w==0?x/w:(x/w)+1;
}
int col(int x){//列号
if(x<=w) return x;
if(row(x)%2==1){ //奇数行
return x%w==0?w:x%w;
}else{ //偶数行
return x%w==0?1:(w-(x%w))+1;
}
}
int main() {
cin>>w>>m>>n;
int result = abs(row(m)-row(n))+abs(col(m)-col(n));
cout<<result;
return 0;
}