(。・∀・)ノ゙
subject
An N × For the number matrix composed of non negative integers of M, you need to take out several numbers so that any two numbers taken out are not adjacent (if a number is adjacent to another number in one of the 88 grids, it is considered that the two numbers are adjacent), and find out the maximum sum of the numbers taken out.
Input format
The first line has a positive integer TT, indicating that there is TT group data.
For each set of data, the first row has two positive integers NN and MM, indicating that the digital matrix is NN row and MM column.
Next, NN rows, MM nonnegative integers per row, describe this numeric matrix.
Output format
TT line, each line is a non negative integer, and the obtained answer is output.
Sample
3
4 4
67 75 63 10
29 29 92 14
21 68 71 56
8 67 91 25
2 3
87 70 85
10 3 17
3 3
1 1 1
1 99 1
1 1 1
Sample results
271
172
99
Problem solution
DFS
Each dfs() selects a number. When there is no optional number, compare the current result pMax with the final result Max and update max
Some questions:
1. Selecting position 0 and then position 3 has the same effect as selecting position 3 and then position 0. How to avoid unnecessary calculation?
First select the low sign and then the high sign, which can also be regarded as a pruning.
Implementation: after the parent node selects a number, it passes the position i behind the number to the child node parameter. The child node starts from i and cannot be selected forward
2. How does the parent node transfer information (which locations are not optional) to the child node?
Introduce the global array pos [] to record whether each position is optional. 1 means optional and 0 means not optional.
After the parent function selects a number, it changes pos [] and then calls the child function. It should be noted that since I use the global variable (pos), after returning from the child function, I have to back out the parent function's operation on pos this time. The advantage of using the global variable is to reduce the time spent in parameter transmission during recursion.
AC code
#include <iostream> #include <string.h> #include <algorithm> #include <vector> using namespace std; int T; int N, M; int D[6+1][6+1];//Used to store each set of data int Max, pMax;//Max is the result of the current group, and pMax saves the intermediate result of each path in the current group of DFS int pos[6*6+5];//It is used to record position information. pos[i] = 1 indicates the position number starting from two-dimensional array D. can I (number starting from 0) be selected at present void dfs(int k){ if(k >= N*M){ Max = max(Max, pMax); return; } int flag = 0; for(int i=k; i<N*M; i++){ if(pos[i]){ //Select the ith position flag = 1; int row, cow; row = i/M; cow = i-M*row; pMax += D[row][cow]; //The lower part is set to the right of i, the lower left, the lower right, and the lower right is 0 int mem[4] = {0}; int old[4] = {0}; if(i+1<N*M && (i+1)/M == row){ //right old[0] = pos[i+1]; pos[i+1] = 0; mem[0] = 1; } if(i+M-1<N*M && (i+M-1)/M == row+1){ //lower left old[1] = pos[i+M-1]; pos[i+M-1] = 0; mem[1] = 1; } if(i+M < N*M){ //Below old[2] = pos[i+M]; pos[i+M] = 0; mem[2] = 1; } if(i+M+1<N*M && (i+M+1)/M == row+1){ //lower right old[3] = pos[i+M+1]; pos[i+M+1] = 0; mem[3] = 1; } dfs(i+1); //Let's roll back pMax and pos pMax -= D[row][cow]; if(mem[0]){ pos[i+1] = old[0]; } if(mem[1]){ pos[i+M-1] = old[1]; } if(mem[2]){ pos[i+M] = old[2]; } if(mem[3]){ pos[i+M+1] = old[3]; } } } if(!flag){ //There are no more numbers to choose from. Compare the results directly Max = max(Max, pMax); } } void init(){ //Initialize some information Max = pMax = 0; for(int i=0; i<N*M; i++){ pos[i] = 1; } } void gmn(){ init(); dfs(0); } int main(int argc, char *argv[]) { cin>>T; for(int i=0; i<T; i++){ cin>>N>>M; for(int i=0; i<N; i++){ for(int j=0; j<M; j++){ cin>>D[i][j]; } } gmn(); cout<<Max<<endl; } return 0; }
improvement
Because the data range of this problem is relatively small, the requirements for recursion times are not very high. In fact, pruning can be carried out. For example, after selecting several data, there may be a gap between these numbers, such as:
Data:
23 21 34 87 22
24 34 33 98 35
33 88 98 78 67
32 78 19 23 76
If you select 23, 22, 33, 98 and 76 in turn, then 34 in the third column of the first row is an optional number, but there is no selected number. Since the problem is the maximum sum, the result of this method must not be the maximum.
My improvement idea: check whether there is a gap regularly. If there is a gap, prune directly. Since each line affects the previous line at most, that is, each line can fill the gap of the previous line at most and cannot fill the previous one, you can detect the previous line of the previous line of i every time you call dfs(i). If a gap is found, prune.
Since I only used pos=0 for the position behind the number before fetching, when using this method, I should use pos=0 for the positions of all numbers in the Jiugong lattice where the number is located
Improved code
#include <iostream> #include <string.h> #include <algorithm> #include <vector> using namespace std; int T; int N, M; int D[6+1][6+1];//Used to store each set of data int Max, pMax;//Max is the result of the current group, and pMax saves the intermediate result of each path in the current group of DFS int pos[6*6+5];//It is used to record position information. pos[i] = 1 indicates the position number starting from two-dimensional array D. can I (number starting from 0) be selected at present //int Counts; void dfs(int k){ //Counts++; if(k >= N*M){ Max = max(Max, pMax); return; } int r = k/M; if(r-2>=0){ r -= 2; for(int i=0; i<M; i++){ if(pos[r*M+i]){ return; } } } int flag = 0; for(int i=k; i<N*M; i++){ if(pos[i]){ //Select the ith position flag = 1; int row, cow; row = i/M; cow = i-M*row; pMax += D[row][cow]; int mem[8] = {0}; int old[8] = {0}; if(i+1<N*M && (i+1)/M == row){ //right old[0] = pos[i+1]; pos[i+1] = 0; mem[0] = 1; } if(i+M-1<N*M && (i+M-1)/M == row+1){ //lower left old[1] = pos[i+M-1]; pos[i+M-1] = 0; mem[1] = 1; } if(i+M < N*M){ //Below old[2] = pos[i+M]; pos[i+M] = 0; mem[2] = 1; } if(i+M+1<N*M && (i+M+1)/M == row+1){ //lower right old[3] = pos[i+M+1]; pos[i+M+1] = 0; mem[3] = 1; } pos[i] = 0;//itself if(i-1 >= 0 && (i-1)/M == row){ //left old[4] = pos[i-1]; pos[i-1] = 0; mem[4] = 1; } if(i-M-1 >= 0 && (i-M-1)/M == row-1){ //upper left old[5] = pos[i-M-1]; pos[i-M-1] = 0; mem[5] = 1; } if(i-M >= 0){ //upper old[6] = pos[i-M]; pos[i-M] = 0; mem[6] = 1; } if(i-M+1 >= 0 && (i-M+1)/M == row-1){ //upper right old[7] = pos[i-M+1]; pos[i-M+1] = 0; mem[7] = 1; } dfs(i+1); //Let's roll back pMax and pos pMax -= D[row][cow]; if(mem[0]){ pos[i+1] = old[0]; } if(mem[1]){ pos[i+M-1] = old[1]; } if(mem[2]){ pos[i+M] = old[2]; } if(mem[3]){ pos[i+M+1] = old[3]; } pos[i] = 1; if(mem[4]){ pos[i-1] = old[4]; } if(mem[5]){ pos[i-M-1] = old[5]; } if(mem[6]){ pos[i-M] = old[6]; } if(mem[7]){ pos[i-M+1] = old[7]; } } } if(!flag){ //There are no more numbers to choose from. Compare the results directly Max = max(Max, pMax); } } void init(){ //Initialize some information Max = pMax = 0; for(int i=0; i<N*M; i++){ pos[i] = 1; } } void gmn(){ init(); dfs(0); } int main(int argc, char *argv[]) { cin>>T; for(int i=0; i<T; i++){ cin>>N>>M; for(int i=0; i<N; i++){ for(int j=0; j<M; j++){ cin>>D[i][j]; } } gmn(); cout<<Max<<endl; } //cout<<Counts<<endl; return 0; }
The test case needs to call dfs()360 times before improvement, but only 276 times after improvement. In fact, there are not many improvements (lll ¬ ω ¬, what better way do you have to communicate in the comment area? Ben Mengxin is happy to reply ̀ ㅂ• ́)و ✧
summarize experience
When doing a question, there was an error in the place to go back at the beginning. I got stuck for a long time and was caught by the method of this global variable. When going back, if the current function is set to pos[i]=0, I will go back to pos[i] = 1. In fact, pos[i] may be 0 at the beginning, and then go back to 1 after setting pos[i]=0. It should be 0
This also taught me A lesson o(╥﹏╥) O: if it is in the form of A=B, you must carefully consider whether A was B before