Week 1: Enumeration

Posted by Immortal55 on Thu, 12 Mar 2020 12:39:12 +0100

Enumeration: a solution strategy based on trying answers one by one

Example 1: perfect cube

Description:
A perfect cubic equation is defined as (a^3) = (b^3) +(c^3) +(d^3). For example, 12, 6, 8, 10. Write a program to find all four tuples (a,b,c,d) for any given positive integer n (n < = 100), so that (a^3) = (b^3) +(c^3) +(d^3) is satisfied, where a,b,c,d is greater than 1, less than or equal to N, and B < = c < = D.

Input:
A positive integer N (N < = 100)

Output:
Output a perfect cube per line.

Input example:

24

Output example:

Cube = 6, Triple = (3,4,5)
Cube = 12, Triple = (6,8,10)
Cube = 18, Triple = (2,12,16)
Cube = 18, Triple = (9,12,15)
Cube = 19, Triple = (3,10,18)
Cube = 20, Triple = (7,14,17)
Cube = 24, Triple = (12,16,20)

Solutions:
Quadruple loop enumeration a, B, c, D, a is in the outermost layer, D is in the innermost layer, and each layer is enumeration from small to large, with the range of a[2,N], b[2,a-1], c[b,a-1], d[c,a-1]

Code:

#include <iostream>
#include <cstdio>//By using the C standard input and output library, the input and output operations can also be implemented in C + +
using namespace std;
int main()
{
	int N,a,b,c,d;
    cin >> N;
	  for(a = 2; a <= N; a++)
	    for(b = 2; b <= a - 1; b++)
	      for(c = 2; c <= a - 1; c++)
	        for(d = 2; d <= a - 1; d++)
	        {
	        	if(N * N * N == a * a * a + b * b * b + c * c * c + d * d * d)	  
              cout << "Cube = "<< N << "Triple = ( "<< a << "," << b << "," << d << ")" << endl;
			}
	return 0;
 }  

Conclusion:

  1. The meaning of Shen Qing
    The question asks you to enter a positive integer, but you don't let yourself judge it
  2. Pay attention to the processing of output content
    cout<<"Cube= "<< N << "Triple = ( " << a <<","<< b <<","<< d << ")" << endl
    Note spaces, variables, etc

Example 2: physiological cycle

Description:
People have the peak days of physical strength, emotional intelligence and IQ. They appear every 23 days, 28 days and 33 days respectively. For everyone, we want to know when the three peaks fall on the same day. Given three peak days p, e, and i (not necessarily the first peak day), given another designated day d, your task is to output day d, and the next three peaks fall on the same day (in days from d). For example, if a given day is 10 and the next three peaks occur on the same day is 12, output 2.

Input:
Enter four integers: P, e, i, and d. p. E, i are the days when the peak of physical strength, emotion and intelligence appears. d is a given day, which may be less than P, e, or i. All given days are nonnegative and less than or equal to 365, and the requested day is less than or equal to 21252.

Output:
From a given day, the next three peaks on the same day.

Input example:

0 0 0 0
0 0 0 100
5 20 34 325
4 5 6 7
283 102 23 320
203 301 203 40
-1 -1 -1 -1

Output example:

Case 1: the next triple peak occurs in 21252 days.
Case 2: the next triple peak occurs in 21152 days.
Case 3: the next triple peak occurs in 19575 days.
Case 4: the next triple peak occurs in 16994 days.
Case 5: the next triple peak occurs in 8190 days.
Case 6: the next triple peak occurs in 10789 days. 

Solutions:
3. From day d+1 until day 21252, for each day D, see whether it meets (D-P)% 23 = = 0 & & (D-E)% 28 = = 0 & & (D-I)% 33 = = 0
4. jump test

Code:

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
  int p,e,i,d, caseNo = 0;
  while(cin >> p >> e >> i >> d && p != -1) {
    int D;
    ++caseNo;
    for(D = d;(D - p) % 23; D++);
    for(;(D - e) % 28;D =+ 23 * 28);
    for(;(D - i) % 33;D =+ 23 * 28 * 33);
    cout << "Case " << caseNo << ": the next triple peak occurs in" << D-d << "days.";
  }
  return 0;
}

Conclusion:

  1. Clever use of for loop statement
    1) for(D=d;(D-p)%23;D + +); since the value is unique, the statement can directly get the answer and carry out the following cycle
    2) The intermediate statement of the for loop is a judgment statement, which can be written as (D-p)%23. If it is true, continue the loop
  2. Integrate statements to make programs easy to read
    1) for recycling
    2)while ( cin >> p >> e >> i >> d && p != -1)

Example 3: weighing coins

Description:
There are 12 coins. There are 11 real coins and one counterfeit. The weight of counterfeit currency is different from that of real currency, but I don't know whether it is heavy or not. Now, use a balance to weigh these coins three times, and tell you the result of weighing. Please find out the counterfeit coins and make sure whether they are light or heavy.
Input example:

1
ABCD EFGH even
ABCI EFJK up
ABIJ EFGH even 

Output example:

K is the counterfeit coin and it is light.   

Solutions:
For each coin, suppose it is light, and see if it is in accordance with the weighing result. If it is, the problem will be solved. If not, assume that it is heavy and see if it is in accordance with the weighing results. Try all the coins and you will find a special one.

Code:

#include <iostream>
#include <cstring>
using namespace std;
char Left[3][10];
char Right[3][10];
char result[3][10];
bool IsFake(char c, bool light);
int main()
{
  int t;
  cin>>t;
  while(t--) {
    for(int i = 0; i < 3; i++)
      cin >> Left[i] >> Right[i] >> result[i];
      for(char c = 'A'; c < 'L'; c++) {
        if(IsFake(c,true)){
          cout << c << " is the counterfeit coin and it is light.\n";    
          break;      
        }
        else if(IsFake(c,false)) {
          cout << c <<" is a counterfeit coin and it is heavy.\n";
          break;
        }
      }
    }
  return 0;
}
bool IsFake(char c, bool light)
{
  for(int i = 0; i < 3; i++) {
    char *pRight, *pLeft;
    if(light) {
      pLeft = Left[i];
      pRight = Right[i];
    }
    else {
      pLeft = Right[i];
      pRight = Left[i];
    }
    switch(result[i][0]){
      case 'u':
        if(strchr(pRight,c) == NULL)
          return false;
        break;
      
      case 'd':
        if(strchr(pLeft,c) == NULL)
          return false;
        break;
      
      case 'e':
        if(strchr(pLeft,c) || strchr(pRight,c))
          return false;
        break; 
    }
  }
  return true;
}

Conclusion:

  1. Pay attention to the inclusion of cycle
    For (int i = 0; I < 3; I + +) statement is only responsible for printing arrays, not the rest
  2. No logical mistakes
    Contents of case 'u', 'e', 'd'
  3. Unclear examination questions
    1) Since there is only one counterfeit currency, the IsFake statement in the main function can be broken as long as it is true once
    2) In IsFake function, for (int i = 0; I < 3; I + +) is responsible for judging and checking coins in three situations. Because only one counterfeit coin can be checked once to get the answer, the return true statement should be located outside the for (int i = 0; I < 3; I + +) loop.
  4. Grammatical problems
    1) case '' statement does not need braces
    2)strchr(char *str,char character)
    Parameter Description: str is a pointer to a string, and character is a character to be found.
    Library name: ාinclude < string. H >
    Function function: find the first occurrence of character from string str.
    Return Description: returns a pointer to the position where the character first appears, or NULL if it is not found.
  5. Sentence integration
    while(t–)

Example 4: light out

Description:
- there is a matrix of buttons with 6 buttons in each row, 5 rows in total
- there is a light at the location of each button
- when a button is pressed, the button and its surrounding position (top, bottom, left,
Right) will change state
- if the light was on, it would be off
- if the lamp was turned off, it will be turned on
·The buttons on the corner of the matrix change the state of the three lights
·The buttons on the edge of the matrix change the state of the four lights
·Other buttons change the status of 5 Lights
- when multiple buttons adjacent to a lamp are pressed, one action cancels out the other
Result
- given the initial state of each lamp in the matrix, find a push button scheme, so that all lamps are off

Input:
- the first line is a positive integer N, indicating the number of cases to be solved
- each case consists of 5 lines, each of which contains 6 numbers
- the numbers are separated by spaces, which can be 0 or 1
- 0 indicates that the initial state of the lamp is off
- 1 indicates that the initial state of the lamp is on

Output:
- for each case, output one line first
·The output string "puzzle ා m", where m is the serial number of the case
- then output 5 lines according to the input format of the case
·1 means to press the corresponding button
·0 means the corresponding button does not need to be pressed
·Each number is separated by a space

Input example:

2
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
0 0 1 0 1 0  
1 0 1 0 1 1
0 0 1 0 1 1
1 0 1 1 0 0
0 1 0 1 0 0

Output example:

PUZZLE#1
1 0 1 0 0 1
1 1 0 1 0 1
0 0 1 0 1 1
1 0 0 1 0 0
0 1 0 0 0 0
PUZZLE#2
1 0 0 1 1 1
1 1 0 0 0 0
0 0 0 1 0 0
1 1 0 1 0 1
1 0 1 1 0 1

Solutions:
Idea 1:
Enumerate all possible button (switch) states, and calculate the condition of the last light for each state to see if it will go out.
——Each button has two states (press or not press)
——There are 30 switches in total, so the number of States is 2 ^ 30. Too many switches will timeout
Idea two:
There is a part. Once the state of the part is determined, the state of the rest parts can only be determined.

Code:

#include <iostream>
#include <string>
#include <cstring>
#include <memory>
using namespace std;
char oriLights[7];
char Lights[7];
char result[7];
int GetBit(char c, int i)
{
  return c& (1 << i);
}
void SetBit(char &c, int i, int v)
{
  if(v)
    c |= (1 << i);
  else 
    c &= ~ (1 << i);
}
void FlipBit(char &c, int i)
{
 c ^= (1 << i); 
}
void OutputResult(int t, char result[])
{
  cout << "PUZZLE#" << t << endl;
  for(int i = 0; i < 5; i++) {
    for(int j = 0; j < 6; j++) {
      cout << GetBit(result[i], j);
      if(j < 5)
        cout << " ";
    }
    cout << endl;
  }
}
int main()
{
  int T;
  cin >> T;
  for(int t = 0; t < T; t++) {
    for(int i = 0; i < 5; i++) {
      for(int j = 0; j < 6; j++) {
        int s;
        cin >> s;
        SetBit(oriLights[i], j, s);
      }
    }
  for(int n=0; n<64; n++) {
    int switchs=n;
    memcpy(Lights,oriLights,sizeof(oriLights));
    for(int i = 0; i < 5; i++) {
      result[i]=switchs;
      for(int j = 0; j < 6; j++) {
        if(GetBit(switchs, j)) {
          if(j > 0)
            FlipBit(Lights[i], j-1);
           FlipBit(Lights[i], j);
           if(j < 5)
             FlipBit(Lights[i], j+1);
        }
      }
      if(i < 4)
        Lights[i+1] ^= switchs;
      switchs = Lights[i];
  }
  if(Lights[4] == 0) {
    OutputResult(t, result);
    break;
  }
  }
}
return 0;
}

Conclusion:

  1. Sequence problem
    1) Judgment statement of newline and space in OutputResult function
    2) Using FlipBit function in main function to judge the position of bit
  2. Topic understanding
    1) The status of the previous line determines the switch light selection of the next line, and the switch light selection of the next line changes the status of the previous line.
    2) End condition of for cycle: turn off all lights in the last line
  3. Bit operation
    1) ^ (XOR): and 1 XOR 1 becomes 0, 0 becomes 1
    2) & (and): 0 is 0
    3) | (or): 1 is 1
    4) (reverse): 1 becomes 0, 0 becomes 1

After class exercise 1: special code lock

Description:
There is a special binary password lock, which is composed of N connected buttons (n < 30). The buttons have two states of concave / convex. Pressing the button by hand will change its state. However, the headache is that when you press a button, the two adjacent buttons will reverse. Of course, if you press the leftmost or rightmost button, it will only affect the button next to it. The current password lock state is known, and the problem to be solved is how many times you need to press the button to change the password lock to the desired target state.

Input:
Two lines, giving two equal length strings composed of 0 and 1, representing the current / target password lock state, where 0 represents concave and 1 represents convex.

Output:
Press the button at least times. If the transformation cannot be realized, the output is impossible.

Input example:

011
000

Output example:

1

Solutions:
1. N < 30, all enumeration spaces are about 536870912, which can not be verified in a short time.
2. Except for the first and last buttons, pressing any button in the middle will change the state of the two adjacent buttons. Therefore, if the state of a certain position button is different from that of the target password lock, and the state of the previous position is already the same, the position button shall not be pressed. The purpose can be achieved by pressing the next position button of this position.
3. Whether the first button is pressed directly determines whether the subsequent button of the whole password lock needs to be pressed. Enumeration space is 2, not 2 ^ 29.

Code:

#include <cstdio> 
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

int oriLock;
int lock;
int destLock;

inline int GetBit(int n,int i)
{
	return (n >> i) & 1;
} 

inline void SetBit(int & n,int i,int v)
{
	if(v) 
		n |= (1 << i);
	else
		n &= ~(1 << i);
}

inline void FlipBit(int & n,int i)
{
	n ^= (1 << i);
}

int main()
{
	char line[40];
	destLock = lock = oriLock = 0;
	cin >> line;
	int N = strlen(line);//Functions of header file < CString >
	for(int i = 0; i < N; ++i)
		SetBit(oriLock,i, line[i] - '0');//There is no difference between GetBit and GetBit. Set one more variable line to calculate the number of password locks
	cin >> line;
	for(int i = 0; line[i]; ++i)
		SetBit(destLock,i, line[i] - '0');
	int minTimes = 1 << 30;//Keep it out of the loop
	for(int p = 0; p < 2; ++p) { 
		lock = oriLock;
		int times = 0;//Put it in the loop to verify the minimum time twice
		int curButton = p;
		for(int i = 0; i < N; ++i) {
			if(curButton) {
				++ times;
				if( i > 0)
					FlipBit(lock,i-1);
				FlipBit(lock,i);
				if( i < N-1)
					FlipBit(lock,i+1);
			}
			if( GetBit(lock,i) != GetBit(destLock,i))  
				curButton = 1;
			else 
				curButton = 0;
		}
		if( lock == destLock)//Advantages of int variable selection
			minTimes = min(minTimes ,times);//Function of header file < algorithm >; record the value of minTimes instead of break
	}
	if( minTimes == 1 << 30)
		cout <<"impossible" << endl;
	else
		cout << minTimes << endl;
	return 0;
}

Conclusion:

  1. Grammatical problems
    1) If char line = 1, int v= line - '1' = 0; int t= line-1 = 48
    2) strlen() calculates the string length, which is included in the cstring header file
    3) Multiply left by 2, divide right by 2
    4) Inline function: to solve the problem that some frequently called small functions consume a lot of stack space. However, it is only suitable for functions with simple internal code of function body, and cannot contain complex structure control statements such as while and switch, and the inline function itself cannot be a direct recursive function.
    5) When you use the = = operator on an array name, the operator compares the starting memory address of the array, not the contents of the array. To compare the contents of two arrays, you must compare their respective elements.
  2. Logic problem
    1) Notice the times, minTimes variable definition location.
    2) The reason for mintimes = 1 < < 30 is that each password is changed in two ways, with a total of 2 * 30 = 60 unit time.

After class exercise 2: clock dialing

Description:
There are nine clocks in a 3 * 3 matrix.

|-------|    |-------|    |-------|
|       |    |       |    |   |   |
|---O   |    |---O   |    |   O   |
|       |    |       |    |       |
|-------|    |-------|    |-------|
    A            B            C    
|-------|    |-------|    |-------|
|       |    |       |    |       |
|   O   |    |   O   |    |   O   |
|   |   |    |   |   |    |   |   |
|-------|    |-------|    |-------|
    D            E            F    
|-------|    |-------|    |-------|
|       |    |       |    |       |
|   O   |    |   O---|    |   O   |
|   |   |    |       |    |   |   |
|-------|    |-------|    |-------|
    G            H            I    
(Figure 1)

Now you need to move the hands of all nine clocks to 12 o'clock with the least amount of movement. A total of 9 different moves are allowed. As shown in the following table, each movement moves the hands of several clocks 90 degrees clockwise.

Clock affected by movement
1         ABDE
2         ABC
3         BCEF
4         ADG
5         BDEFH
6         CFI
7         DEGH
8         GHI
9         EFHI

Input:
9 integers, indicating the starting position of each clock pointer, separated by a single space between two adjacent integers. Among them, 0 = 12 points, 1 = 3 points, 2 = 6 points, 3 = 9 points.

Output:
Output a shortest moving sequence so that the nine clock pointers all point to 12. Output the result according to the moving sequence number from small to large. Two adjacent integers are separated by a single space.

Input example:

3 3 0 
2 2 2 
2 1 2

Sample output:

4 5 8 9

Solutions:
Enumeration of violence

Code:

//Solution 1: recursion 
#include <iostream>
#include <bitset>
#include <algorithm>
#include <functional>
#include <cstring>
using namespace std;

int oriClocks[9];
int clocks[9];
const char * moves[9] = { "ABDE","ABC","BCEF","ADG","BDEFH","CFI","DEGH","GHI","EFHI" };
int moveTimes[9] = {0};
int result[9];
int minTimes = 4*9;

void Enum(int n) 
{
	if( n >= 9 ) {
		memcpy(clocks,oriClocks,sizeof(clocks));
		int totalTimes = 0;
		for( int i = 0;i < 9 ; ++ i ) { 
			if( moveTimes[i] ) { 
				for( int k = 0; moves[i][k]; ++k) {
					clocks[moves[i][k]-'A'] = (clocks[moves[i][k]-'A'] + moveTimes[i]) % 4;//Calculate remainder
					totalTimes += moveTimes[i];
				}
			}
		}

		int i;
		for( i = 0;i < 9; ++i )
			if( clocks[i])
				break;//The existing clock is not 12, move failed
		if( i == 9) {
			if( minTimes > totalTimes) {
				minTimes = totalTimes;
				memcpy(result,moveTimes,sizeof(result)); 
			} 
		}

		return ;
	}

	for( int i = 0;i < 4; ++ i ) {
		moveTimes[n] = i;
		Enum(n+1);
	}
	return ;
} 

int main()
{
	for( int i = 0;i < 9 ; ++i )
		cin >> oriClocks[i];
	Enum(0);
	for( int i = 0; i < 9; ++i )//Traverse every move mode
		for( int k = 0; k < result[i] ; ++ k )//Number of traversal moves
			cout << i+1 << " ";
	return 0;
}
//Some recursive results are as follows:
/*
moveTimes={0,0,0,0,0,0,0,0,0,}
moveTimes={0,0,0,0,0,0,0,0,1,}
moveTimes={0,0,0,0,0,0,0,0,2,}
moveTimes={0,0,0,0,0,0,0,0,3,}
There's only eight possibilities 
moveTimes={0,0,0,0,0,0,0,1,0,}
moveTimes={0,0,0,0,0,0,0,1,1,}
moveTimes={0,0,0,0,0,0,0,1,2,}
moveTimes={0,0,0,0,0,0,0,1,3,}

moveTimes={0,0,0,0,0,0,0,2,0,}
moveTimes={0,0,0,0,0,0,0,2,1,}
moveTimes={0,0,0,0,0,0,0,2,2,}
moveTimes={0,0,0,0,0,0,0,2,3,}

moveTimes={0,0,0,0,0,0,0,3,0,}
moveTimes={0,0,0,0,0,0,0,3,1,}
moveTimes={0,0,0,0,0,0,0,3,2,}
moveTimes={0,0,0,0,0,0,0,3,3,}
7+8 The possibility of 
*/

Conclusion:

  1. Grammatical problems
    1) bitset creates an array of fixed size containing bits or Booleans. The bitset template class can be used when you need to manage various identities and represent variables in any combination of identities.
    2) Pay attention to the usage of memcpy.
  2. Logic problem
    1) Recursion starts from n=8, moveTimes[8]=0,1,2,3, and enumerates only move mode 8; then returns to the previous level, moveTimes[7]=0,Enum(9) gets moveTimes[8]=1 again, and enumerates move mode 7 + 8, and so on.
Published 3 original articles, won praise 1, visited 40
Private letter follow

Topics: less REST