I used to know that the Joseph problem was a simulation. Today I found that some Joseph problems can be obtained through mathematical solutions! Really powerful! Joseph's problem is profound and profound! Of course, we should only simulate the variable length of the report. What we can do with mathematics is the simplified Joseph problem. The following is an example:
1. Problem description: N people (Number 1 ~ N), report data from 1, report data to m, and report data from 1. Number of the output columns in sequence. Complexity of the mathematical solution: O (n ). The following code is taken from feiyan's blog in the rain. I haven't understood this formula yet... # Include <stdio. h> # Include <conio. h> Int main (void) { Int N, I = 0, M, P; Scanf ("% d", & N, & M); // n total, M step While (++ I <= N) { P = I * m; While (P> N) P = p-n + (p-n-1)/(m-1 ); Printf ("% d/N", P ); } Getch (); Return 0; } 2. Problem description: N people (numbered 1 ~ N), report data from 1, report data to m, and report data from 1. Calculate the number of the winner. Complexity of the mathematical solution: O (n ).
Multiple reprints are not identified by the author, but they are quite well written... Both linked list implementation and array implementation have one thing in common: to simulate the entire game process, not only do the program write more annoying, but the time complexity is as high as O (NM), when n, when M is very large (for example, millions or even tens of millions), there is almost no way to produce results in a short time. We noticed that the original problem only requires the number of the last winner, rather than the whole process being simulated by the reader. Therefore, if efficiency is to be pursued, we must break the regular rules and implement some mathematical strategies. To facilitate the discussion, change the problem slightly without affecting the original intention: Problem description: N people (No. 0 ~ (N-1), reporting starts from 0, reporting ends from m-1), and reporting continues from 0. Calculate the number of the winner. We know that after the first person (number must be M % N-1) is listed, the remaining n-1 person forms a new Joseph ring (starting with a person numbered K = m % N ): K + 1 K + 2... N-2, n-1, 0, 1, 2,... K-2 And 0 is reported from K. Now let's convert their numbers: K --> 0 K + 1 --> 1 K + 2 --> 2 ... ... K-2> N-2 K-1 --> n-1 After the transformation, it will completely become a subproblem of (n-1) the number of individual reports. If we know the solution of this subproblem: for example, X is the final winner, so it's just n people's situation to change X back Based on the table above ?!! The formula for changing back is very simple. I believe everyone can introduce it: x' = (x + k) % N How can I solve the problem of (n-1) number of personal reports? Yes, as long as you know (n-2) the individual's solution. (N-2) What about personal solutions? Of course it is the first (n-3) situation ---- this is obviously a reverse push problem! Well, the idea is coming out. The recursive formula is as follows: F [I] indicates that I personally play the game and report m to exit the number of the final winner. The final result is f [N]. Recurrence Formula F [1] = 0; F [I] = (F [I-1] + M) % I; (I> 1) With this formula, we need to calculate the value of F [I] From the 1-N order, and the final result is f [N]. Because the number in real life always starts from 1, we Output F [N] + 1 Because it is a step-by-step recursion, it does not need to save every f [I], and the program is also very simple: # Include <stdio. h> Int main () { Int n, m, I, S = 0; Printf ("n m ="); scanf ("% d", & N, & M ); For (I = 2; I <= N; I ++) S = (S + M) % I; Printf ("the winner is % d/N", S + 1 ); } The time complexity of this algorithm is O (n), which has greatly improved compared with the simulation algorithm. N, m is equal to 1 million, and 10 million is not a problem. 3. Problem description: N people (numbered 1 ~ N), report data from 1, report data to M (M <n), and report data from 1. Calculate the number of the winner. Complexity after optimization of the mathematical solution: O (m ).
Also taken from the internet, it seems like a thesis, which is not identified by the author... Compared with the initial simulation algorithm, the efficiency of the above algorithm has been greatly improved. Is there room for improvement in this algorithm? In fact, if we observe the variable s in the above algorithm, its initial value is the number of the first outbound person, but in the process of loop, we will find that it is often in an incremental state of equality. Let me see this formula: S = (S + M) % I;, we can see that, when I is large and S + S-1 is small, S is in an incremental state. This incremental process is not necessary and can be skipped. Let's set the intermediate variable X to list the following equations: S + M * X-1 = I + x Solve X, and assign I + X to I by S = S + M * X. In this way, the loop with X duplicates in the middle is skipped, this reduces the time overhead for increasing the variance. However, the obtained x + I may exceed n. In fact, this result tells us that the algorithm can be ended directly.
The C language of the entire algorithm is described as follows: Long Joseph PHUs (long N, long M, long K) // number of people, outbound step, enable reporting location, { If (M = 1) k = 1? N: (K + n-1) % N; Else { For (long I = 1; I <= N; I ++) { If (K + M) <I) { X = (I-k + 1)/(m-1)-1; If (I + x <n) { I = I + X; K = (k + M * X ); } Else { K = K + M * (N-I ); I = N; } } K = (k + m-1) % I + 1; } } Return K; // return the position of the last person }
The complexity of the algorithm is no longer related to the number of people in a circle at m <n, even if n = 2000000000, M = 3, S = 1, in fact, most of the cases are m <n, and m is relatively small. At this time, the complexity of this algorithm is only O (m ); however, when m> = N, the number of cyclic duplicates cannot be reduced by the values obtained using the equation, and the complexity of the algorithm is still O (n ).
4. Problem description: N people (numbered 1 ~ N). Report the number starting from 1, report to 2, and report the number from 1. Calculate the number of the winner. Complexity after mathematical solution optimization: O (log n)
For details, refer to the discussion in the related section of "Specific mathematics" by Donald E. knuth. (Click here) At this time, there is a simpler recursive formula: J (1) = 1; J (2n) = 2j (n) −1, when n is ≥1; J (2n + 1) = 2j (n) + 1, when n is ≥1; Then we can launch: J (2 ^ m + l) = 2L + 1,WhenM ≥ 0And0 ≤ L <2 m. (Note that if2 ^ m ≤ n <2 ^ m + 1,Then the remaining numberL = n−2 ^ mInequality0 ≤ L <2 ^ (m + 1) −2 ^ m = 2 ^ m.) Looking at the formula is a headache. In fact, it is to find the X power (counted as m) of the smallest 2 greater than N ), Then 2n-m + 1 is the result. Should programming be simple? The following is a reprinted copy. The original author is unknown. If you continue to push it down, you can get: X = 2 * n + 1-(2 * n + 1-2 * k) * 2 ^ log2 (2 * n) /(2 * n + 1-2 * k )) Here, log2 (2 * N)/(2 * n + 1-2 * K) is calculated as (2 * n) /(2 * n + 1-2 * k) Base on 2 logarithm, Returns an integer down. Contact 2 ^ log2 (2 * N)/(2 * n + 1-2 * K) /(2 * n + 1-2 * k) Down Returns the power of 2. In some cases, this operation is called a floor function. We define it as flp2. below is C language implementation:
Unsigned flp2 (unsigned X) { Unsigned y; Do {Y = x; X & = X-1;} while (X ); Return y; } Where the X & = X-1; statement is to change the rightmost 1 of the X binary to 0 each time until the leftmost 1. This method can also be used to calculate the number of 1 in X binary, when the number of 1 in X binary is relatively small The algorithm efficiency is very high. Implementation of code with M 2: Unsigned Joseph phus2k (unsigned N, unsigned K) { Unsiged t = (n <1)-(k <1) + 1; Return (n <1) + 1-T * flp2 (n <1)/t ); } |