Algorithmic problem solving (I) -- divide and conquer -- confrontation grouping
1, Title
Content description
Number from 1 1 1 to n n n's students compete in groups: the competition is divided into multiple rounds, and all members participate in each round. The students are divided into two groups. Each group must have at least one student. There is an antagonistic relationship between students in different groups. In the whole competition, each pair of students has had a confrontation relationship. Please give a scheme with the least number of rounds.
input
Number of students n n n( 2 ≤ n l e q 1000 2 \leq n leq 1000 2≤nleq1000).
output
The first row outputs the least number of rounds m m m. Then m m m lines output the total number and corresponding number of the first or second group in each round, and the numbers are separated by spaces.
Sample 1 1 1
Input:
2
\quad Output:
1 1 1
Sample 2 2 2
\quad Input:
5
\quad Output:
3 1 1 3 1 2 3 2 2 4
2, Train of thought 1 1 1: Binary
Inference (if you don't understand, read the description first)
- In a round of grouping, a student in the first group is recorded as 1 1 1. In the second group, it is recorded as 0 0 0, then k k In the k-round grouping, the student and one k k k-bit binary numbers form a one-to-one relationship (injective);
- If the binary numbers corresponding to two students are different, there is an antagonistic relationship;
- If the binary numbers corresponding to all students are different, all students will fight against each other;
- Number of students n n n. Number of rounds k k k. Then n ≤ 2 k n \leq 2^k n≤2k.
\quad prove:
- According to the above definition, one student cannot correspond to multiple binary numbers; In addition, multiple students cannot correspond to the same binary number, otherwise these students have been divided into the same group and do not meet the "confrontation";
- If two students are always divided into a group, the binary numbers corresponding to them are the same, and the inverse no proposition is the conclusion;
- By inference 2 2 2 know, obviously;
- k k k-bit binary number common 2 k 2^k 2k, the necessary condition for injectivity is that the basis of the definition domain is not greater than that of the value domain, i.e n ≤ 2 k n \leq 2^k n≤2k.
explain
Analysis example 2 2 2. It is assumed that these outputs are members of the first group for ease of description. classmate 1 1 1 only the first and second rounds are divided into the first group: 110, students 2 2 2 only the second and third rounds are divided into the first group: 011, students 3 3 3 only the second round in the first group: 010, classmate 4 4 4 only the third round is divided into the first group: 001, students 5 5 5 three rounds are not in the first group: 000. Each student's corresponding binary number is different, so they fight each other.
from 2 2 < 5 ≤ 2 3 2^2 < 5 \leq 2^3 22 < 5 ≤ 23 is known, in order to meet the inference 4 4 4. Minimum number of rounds k = 3 k = 3 k=3. Similarly, it is easy to know, n = 6 , 7 , 8 n = 6, 7, 8 When n=6,7,8, the minimum number of rounds is k = 3 k = 3 k=3.
conclusion
Minimum number of rounds k = ⌈ log 2 n ⌉ k = \lceil\log_2n\rceil k=⌈log2n⌉. Group: each student corresponds to a different k k k-bit binary number (there is no sequential output requirement here, so the order is not important and can be matched arbitrarily), and then calculate the second binary number 1 1 1 bit is 1 1 The number of students of 1 is divided into the first group, and the corresponding number of students is output. Next, the binary number is calculated 2 2 2 bits are 1 1 1, and output the corresponding number of students; Repeat, total k k k wheel. Essence: reverse operation of description.
C implementation 1 1 1
#include <stdio.h> #include <string.h> char *itobs(int n, char *ps, int size); // The number n is converted into a binary string with a length of size and stored in ps int main() { int N; scanf("%d", &N); int round = 0, n; // Get the minimum number of rounds for (n = 1; n < N; n *= 2) round++; int i, j; int pep_num[round]; // Number of people in the first group of each round char a[N][round + 1]; // Binary string corresponding to each student for (i = 0; i < round; i++) pep_num[i] = 0; // Match the i-th student with the binary string with the value of I (it can also be matched in other ways, just shoot alone), and count the total number of students in the first group in round j for (i = 0; i < N; i++) { itobs(i, a[i], round); for (j = 0; j < round; j++) { if (a[i][j] == '1') pep_num[j]++; } } // output printf("%d\n", round); for (j = 0; j < round; j++) { printf("%d", pep_num[j]); for (i = 0; i < N; i++) { if (a[i][j] == '1') printf(" %d", i + 1); } if (j < round - 1) printf("\n"); } return 0; } char *itobs(int n, char *ps, int size) { int i; for (i = size - 1; i >= 0; i--, n >>= 1) ps[i] = (01 & n) + '0'; ps[size] = 0; return ps; }
The complexity of the algorithm is n l o g 2 n nlog_2n nlog2n.
3, Train of thought 2 2 2: Divide and conquer
inference
A group of n people fight in pairs ⇐ \Leftarrow ⇐ n n n individuals were divided into two groups, two groups against each other and two against each other within the group.
\quad prove:
Two groups were set up G 1 = { s 1 , s 2 , ⋯ , s k } G_1 = \{s_1, s_2, \cdots, s_k\} G1={s1,s2,⋯,sk}, G 2 = { s k + 1 , ⋯ , s n } G_2 = \{s_{k+1}, \cdots, s_n\} G2={sk+1,⋯,sn}( k < n k < n K < n), one of them s i s_i si, let's assume s i ∈ G 1 s_i \in G_1 si ∈ G1 is obtained by two groups of confrontation s i s_i si ^ and G 2 G_2 G2 total n − k n - k n − k different people against each other, from two to two in the group s i s_i si ^ and G 1 G_1 G1 total k − 1 k - 1 k − a different person, and G 1 ∩ G 2 = ∅ G_1 \cap G_2 = \varnothing G1 ∩ G2 = ∅, so s i s_i si , and Co n − 1 n - 1 n − 1 different person confrontation, by s i s_i The arbitrariness of si +, n n n people fight in pairs.
C implementation 2 2 2
#include <stdio.h> int a[10][1000], top[10], Round; // A is the members of a group in each Round of grouping, top is the total number of people in each Round, and Round is the minimum number of rounds void group(int left, int right, int round); int main() { int n, i, j; scanf("%d", &n); group(0, n - 1, 0); // output printf("%d\n", Round + 1); for (i = 0; i < Round + 1; i++) { printf("%d ", top[i]); for (j = 0; j < top[i]; j++) printf("%d ", a[i][j]); printf("\n"); } return 0; } void group(int left, int right, int round) { if (left <= right) { if (round > Round) Round = round; // Real time update rounds int mid = (left + right + 1) / 2; // Try to divide equally. If there is the most confrontation relationship, there will be the least number of rounds int i; for (i = mid; i <= right; i++) { a[round][top[round]] = i + 1; top[round]++; } group(left, mid - 1, round + 1); // Recursive processing of left group group(mid + 1, right, round + 1); // Recursive processing right group } }
The complexity of the algorithm is O ( n l o g 2 n ) O(nlog_2n) O(nlog2n).
4, Summary
The binary method is only deduced by observing the law. It is suggested to master the idea of divide and Conquer:
The original problem is decomposed into several small-scale subproblems similar to the original problem, these subproblems are solved recursively, and then the solutions of these subproblems are combined to establish the solution of the original problem.