(Turn) Joseph ring problem Joseph ring problem (the simplest mathematical solution)

Original blog http://www.cnblogs.com/cmmdc/p/7216726.html

About the inference process of the core idea of ​​Joseph ring, this article is more detailed

 

------------------------The following are copy and paste-------------------- ------------

 

Basic problem description:
n people (represented by numbers 1, 2, 3...n) are known to sit around a round table. Start counting from the person numbered 1, and the person who counts to m is dequeued; the next person starts counting from 1, and the person who counts to m is dequeued; repeat this pattern until around the round table of people are all listed. (It is also similar to the perverted murderer problem) Usually when solving this kind of problem, we number from 0 to n-1, and the final result +1 is the solution of the original problem. Usually, we will ask to output the serial number of the last person to be dequeued. So the main research here is how to determine the serial number of the last person listed.

 

When the amount of n, m data is small, we can use a circular linked list to simulate the process of the Joseph ring. When the number of people in the simulation is equal to 1, the serial number of the remaining people can be output. Specific solution This method is often relatively simple to implement and easy to understand. But the time complexity is very bad, reaching O(n m). In this case, in fact, when n and m are relatively large (n m reaches 10^8 or more), it often takes time to get the result. A long time, but we can use a little bit of math to deduce the final result.

 

In order to simplify the process of dequeuing:
first, we number the serial numbers of the n people from 0 to n-1 (the reason is very simple, because m may be greater than n, and when m is greater than or equal to n, then the first dequeuing The person number is m%n, and m%n may be equal to 0, so the numbering can simplify the process of subsequent dequeuing), when the person who counts to m-1 is dequeued, so after we complete the numbering, we start to analyze the Column process:
First dequeue:
At the beginning, the pattern of all the numbers in sequence is:
0, 1, 2, 3, 4, 5...n-2, n-1
then the first The number of the person who is dequeued at one time is (m-1)%n1, then after the first person is dequeued, the next person starts to count from 0. For convenience, we set k1 = m% n1 (n1 is the total number of people in the current sequence), then after the first person is dequeued, k1 is the first element of the next new numbering sequence, then the new numbering sequence we get is:
k1, k1+1, k1 +2, k1+3...n-2, n-1, 0, 1, 2...k1-3, k1-2 (k1-1 is dequeued for the first time)
then in this new sequence , the first person still counts from 0, then in this new sequence, the corresponding numbers reported by each person are:
0, 1, 2, 3....n-2
, then the second time everyone reports The relationship between the corresponding number of the first time and the corresponding number of the first time is:
0 --> k1
1 --> k1+1
2 --> k1+2
...
n-2 ---> (k1 +n-2)%n1 (n1 is the total number of people in the current sequence, because it is a cyclic sequence, k1+n-1 may be greater than the total number of people)
Then the problem we need to solve at this time is the problem of reporting the number of n-1 people ( That is, the problem of the n-1 order Joseph ring)

 


Maybe the above process is still not clear to you, then we repeat the above process and continue to deduce the problem of the Joseph ring of the remaining n-1 people:
then among the remaining n-1 people, we can also use this for convenience. The number of n-1 people is:
0,1,2,3,4...n-2
, then the number of people who are dequeued at this time is (m-1) % n2 (n2 is the total number of people in the current sequence), Similarly, we set k2 = m % n2, then after the person is delisted, the sequence is rearranged, and the new numbering sequence after rearrangement is:
k2, k2+1, k2+2, k2+3...n- 2, n-1, 0, 1, 2...k2-3, k2-2 (k2-1 has been dequeued for the first time)
Then in this new sequence, the first person still reports from 1. number, then in this new sequence, the corresponding numbers reported by each person are:
1, 2, 3, 4....n-2
Then does this transform the problem into the n-2 order Joseph ring again? The problem?
The latter process is exactly the same as the previous two processes, so the recursive processing continues until there is only one person left, and the result can be directly obtained.
When we get one person (that is, the first-order Joseph ring problem), So can we deduce the result of the second-order Joseph ring from the result of the first-order Joseph ring problem?
With the help of the above analysis process, we know that when solving the n-order Joseph ring problem, after the person with the serial number k1 is dequeued, the remaining n-1 people re-form a n-1 order Joseph ring, then
if The result of this n-1 order Joseph ring problem is ans (that is, the last person to be dequeued is numbered ans), then through the above analysis process, we can know that the result of the n-order Joseph ring
(ans + k)%n (n is the total number of people in the current sequence), and k = m%n
has:
the result of the n-order Joseph ring

(ans + m % n)%n, then we can also simplify the formula as follows:

当m<n时,易得上式可化简为:(ans +="" m)%="" n="" 而当m="">=n时,那么上式则化简为:(ans % n + m%n%n)% n
即为:(ans % n + m%n)% n
而 (ans + m)% n = (ans % n + m%n)% n
因此得证
(ans + m % n)%n = (ans + m)% n
这样的话,我们就得到了递推公式,由于编号是从0开始的,那么我们可以令
f[1] = 0; //当一个人的时候,出队人员编号为0
f[n] = (f[n-1] + m)%n //m表示每次数到该数的人出列,n表示当前序列的总人数
而我们只需要得到第n次出列的结果即可,那么不需要另外声明数组保存数据,只需要直接一个for循环求得n阶约瑟夫环问题的结果即可
由于往往现实生活中编号是从1-n,那么我们把最后的结果加1即可。

代码:

#include <stdio.h>
int main() { int n, m, i, s = 0; printf ("N M = "); scanf("%d%d", &n, &m); for (i = 2; i <= n; i++) { s = (s + m) % i; printf("%d\n",s); } printf ("\nThe winner is %d\n", s+1); }

基本问题描述:
已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为1的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。(也类似于变态杀人狂问题)通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解。通常,我们会要求输出最后一位出列的人的序号。那么这里主要研究的是最后一个出列的人的序号要怎么确定。

 

当n,m数据量很小的时候,我们可以用循环链表模拟约瑟夫环的过程。当模拟到人数等于1的时候,输出剩下的人的序号即可。
具体解法这种方法往往实现起来比较简单,而且也很容易理解。但是时间复杂度却是很糟糕的,达到了O(nm),这样的话,其实在n,m比较大的时候(nm达到10^8或者更大),那么要得出结果往往需要耗费很长的时间,但是我们可以运用一点数学上的技巧,将最后结果推导出来。

 

为了简化出列的过程:
首先我们把这n个人的序号编号从0~n-1(理由很简单,由于m是可能大于n的,而当m大于等于n时,那么第一个出列的人编号是m%n,而m%n是可能等于0的,这样编号的话能够简化后续出列的过程),当数到m-1的那个人出列,因此我们编号完成之后,开始分析出列的过程:
第一次出列:
一开始的时候,所有人的编号排成序列的模式即为:
0,1,2,3,4,5...n-2,n-1
那么第一次出列的人的编号则是(m-1)%n1,那么在第一个人出列之后,从他的下一个人又开始从0开始报数,为了方便我们设k1 = m%n1(n1为当前序列的总人数)那么在第一个人出列之后,k1则是下一次新的编号序列的首位元素,那么我们得到的新的编号序列为:
k1,k1+1,k1+2,k1+3...n-2,n-1,0,1,2...k1-3,k1-2 (k1-1第一次已出列)
那么在这个新的序列中,第一个人依旧是从0开始报数,那么在这个新的序列中,每个人报的相应数字为:
0,1,2,3....n-2
那么第二次每个人报的相应数字与第一次时自己相应的编号对应起来的关系则为:
0 --> k1
1 --> k1+1
2 --> k1+2
...
n-2 ---> (k1+n-2)%n1(n1为当前序列的总人数,因为是循环的序列,k1+n-1可能大于总人数)
那么这时我们要解决的问题就是n-1个人的报数问题(即n-1阶约瑟夫环的问题)

 


可能以上过程你还是觉得不太清晰,那么我们重复以上过程,继续推导剩余的n-1个人的约瑟夫环的问题:
那么在这剩下的n-1个人中,我们也可以为了方便,将这n-1个人编号为:
0,1,2,3,4...n-2
那么此时出列的人的编号则是(m-1) % n2(n2为当前序列的总人数),同样的我们设k2 = m % n2,那么在这个人出列了以后,序列重排,重排后新的编号序列为:
k2,k2+1,k2+2,k2+3...n-2,n-1,0,1,2...k2-3,k2-2 (k2-1第一次已出列)
那么在这个新的序列中,第一个人依旧是从1开始报数,那么在这个新的序列中,每个人报的相应数字为:
1,2,3,4....n-2
那么这样的话是不是又把问题转化成了n-2阶约瑟夫环的问题呢?
后面的过程与前两次的过程一模一样,那么递归处理下去,直到最后只剩下一个人的时候,便可以直接得出结果
当我们得到一个人的时候(即一阶约瑟夫环问题)的结果,那么我们是否能通过一阶约瑟夫环问题的结果,推导出二阶约瑟夫环的结果呢?
借助上面的分析过程,我们知道,当在解决n阶约瑟夫环问题时,序号为k1的人出列后,剩下的n-1个人又重新组成了一个n-1阶的约瑟夫环,那么
假如得到了这个n-1阶约瑟夫环问题的结果为ans(即最后一个出列的人编号为ans),那么我们通过上述分析过程,可以知道,n阶约瑟夫环的结果
(ans + k)%n(n为当前序列的总人数),而k = m%n
则有:
n阶约瑟夫环的结果

(ans + m % n)%n,那么我们还可以将该式进行一下简单的化简:

当m<n时,易得上式可化简为:(ans +="" m)%="" n="" 而当m="">=n时,那么上式则化简为:(ans % n + m%n%n)% n
即为:(ans % n + m%n)% n
而 (ans + m)% n = (ans % n + m%n)% n
因此得证
(ans + m % n)%n = (ans + m)% n
这样的话,我们就得到了递推公式,由于编号是从0开始的,那么我们可以令
f[1] = 0; //当一个人的时候,出队人员编号为0
f[n] = (f[n-1] + m)%n //m表示每次数到该数的人出列,n表示当前序列的总人数
而我们只需要得到第n次出列的结果即可,那么不需要另外声明数组保存数据,只需要直接一个for循环求得n阶约瑟夫环问题的结果即可
由于往往现实生活中编号是从1-n,那么我们把最后的结果加1即可。

代码:

#include <stdio.h>
int main() { int n, m, i, s = 0; printf ("N M = "); scanf("%d%d", &n, &m); for (i = 2; i <= n; i++) { s = (s + m) % i; printf("%d\n",s); } printf ("\nThe winner is %d\n", s+1); }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324712988&siteId=291194637