跑圈问题
1
2
3
4
5
6
unsigned short i,j;
int count = 0;
for (i= 0, j=2; i!=j; i+=5, j+=7) {
count++;
}
// 此时count是多少?
1、通用解法
很显然,当i
和j
相遇的时候,他们俩必然在同一个位置。好吧,这是一句大废话。不过这句废话怎么表示呢?
1
2
3
4
5
//i的步长是5, j的步长是7。假设他们x步后相遇,所以他们走过的总路径分别是
long iSum = 5 * x;
long jSum = 7 * x + 2; //起始位置算在总路径中
// 那么他们现在的位置相等
iSum % 65536 == jSum % 65536; //此表达式为真
好了,经过上面的分析,通用解法已经出来了。
1
2
3
4
5
6
7
int count = 0;
while (1) {
if ((7 * count + 2) % 65536 == (5 * count) % 65536) {
break;
}
count++;
}
这个循环,跑去吧。
2、改进解法
通用解法优点是很简单,很容易理解。但是,一旦模的值变大,循环次数太多,更本不是人能算出来的,不信?你自己算算上面那个答案。
该怎么简化呢?注意下这个等式:
1
iSum % 65536 == jSum % 65536;
取余操作是很麻烦的,而且我们穷举的数值是sum值,一步步在累加,这样实在太麻烦了。
1
2
iSum % 65536 == jSum % 65536 ==>
iSum - jSum == 65536 * n //n是某个合适的值
上面的推导过程不详细说明了,很简单。
1
2
7 * count + 2 - 5 * count == 65536 * n;
count = (65536 * n - 2) / 2
好了,直接求count的算法就出来了。有一点需要注意,count 是一个整数。所以需要加一步判断。
1
2
3
4
5
6
7
8
9
10
int count = 0;
int n = 1;
while (n > 0) {
int temp = 65536 * n - 2;
if (!(tmep % 2)) {
count = temp / 2;
break;
}
n++;
}
好了,这个算法循环的次数明显要比上一个小好多好多,并且我们自己也可以算出答案。对这个题来说,n = 1
的时候就是合适的值,只用循环一次就好。
可以看出,上面的改进解法可以作为一般的解题思路。我们可以写这么一段代码作为通用代码,使用的时候只需要替换几个参数就可以了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int getCount(int mod, int aheadStep, int vDiff) {
int count = -1;
int n = 1;
// 速度差不小于1
if (vDiff < 1) {
return -1;
}
// 如果没找到,n溢出后变成负数退出
while (n > 0) {
int temp = mod * n - aheadStep;
if (!(tmep % vDiff)) {
count = temp / vDiff;
break;
}
n++;
}
return count;
}