How to use memoization in counting a large number of matrices
我得到了一个程序,该程序需要我计算矩阵以前状态的数量。
给定的矩阵是布尔矩阵。我将对
如果考虑以下四个单元,则矩阵中单元的下一个状态为
- 细胞本身
- 正确的细胞
- 下面的单元格
- 下方和右侧的单元格,
在这4个单元中只有一个
如果给定的矩阵(M)为:
0 0 0 1
0 0 1 0
然后,对于第一个单元格(M [0] [0]),要考虑的四个单元格分别为M [0] [0],M [0] [1],M [1] [0]和M [1] [1]。因此,第一个单元格的下一个状态是
对于第二个像元(M [0] [1]),要考虑的四个像元是M [0] [1],M [0] [2],M [1] [1],M [1] [ 2]。因此,此单元格的下一个状态是
这样,此矩阵(M)的下一个状态将是矩阵(N):
0 1 0
显然,下一个状态将比前一个状态少1行1列。因此,矩阵的给定状态可以具有许多先前的状态,例如,除了矩阵M之外,给定矩阵:
1 0 0 0
1 1 0 0
还将具有下一个状态N。
我必须计算给定矩阵具有的先前状态的数量。
我写了以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | public class Answer2 { static boolean[][] main_array,answer_array; // answer_array is the 2D array given to me. main_array is the 2D array which I recurse through, and then find its solution to compare with answer_array. static int c; // counter static int answer_array_height,answer_array_width; // matrix height and matrix width public static int answer(boolean[][] boolean_array) { answer_array = boolean_array; main_array = new boolean[answer_array.length+1][answer_array[0].length+1]; c=0; answer_array_height = answer_array.length; answer_array_width = answer_array[0].length; recurse(1,1); main_array[0][0] = true; recurse(1,1); return c; } public static String pad(String s, int l){ //Add 0's to the beginning of the string till its length equals l for(int i=s.length(); i<l; i++) s='0'+s; return s; } public static void recurse(int w, int h){ if(w==answer_array_width+1 && h==answer_array_height+1){ c++; return; } //System.out.println(java.util.Arrays.deepToString(main_array).replace("],","],\ ").replace("true","1").replace("false","0")); if(h==answer_array_height+1 || h>=w){//Add column int x = 0; for(int i=0; i<h; i++) x+=(int)Math.pow(2,i); //This will give me the integer representation of max value(whose binary representation will be used to put values in the matrix) to handle. for(int i=0; i<=x; i++){ String str = pad(Integer.toBinaryString(i),h); for(int j=0; j<h; j++){ main_array[j][w]= str.charAt(j)=='1'; //set main_array[j][w] true wherever the binary representation of i has 1. This recurses through all the combinations. } if(check(w+1,h,false)){ recurse(w+1, h); }else{ for(int j=0; j<h; j++){ main_array[j][w]=false; } } } }else{//Add row int x = 0; for(int i=0; i<w; i++) x+=(int)Math.pow(2,i); for(int i=0; i<=x; i++){ String str = pad(Integer.toBinaryString(i),w); for(int j=0; j<w; j++){ main_array[h][j]= str.charAt(j)=='1'; } if(check(w,h+1,true)){ recurse(w, h+1); }else{ for(int j=0; j<w; j++){ main_array[h][j]=false; } } } } } // w is the effective width, h is the effective height, height_was_increased is true if height was increased, false if width was increased. //height_was_increased helps to shorten the time used for comparison as the matrix was correct before the width or height was increased. So it just needs to check the increased portion. public static boolean check(int w, int h, boolean height_was_increased){ if(height_was_increased){ for(int j=0; j<w-1; j++){ //I know this part is complex. It just finds out the answer of the four cells to be considered and matches it with the given matrix. if(answer_array[h-2][j] != (main_array[h-2][j]^main_array[h-2+1][j]^main_array[h-2][j+1]^main_array[h-2+1][j+1] && !(main_array[h-2][j] && main_array[h-2+1][j]) && !(main_array[h-2][j+1] && main_array[h-2+1][j+1]))) return false; } }else{ for(int i=0; i<h-1; i++){ if(answer_array[i][w-2] != (main_array[i][w-2]^main_array[i+1][w-2]^main_array[i][w-2+1]^main_array[i+1][w-2+1] && !(main_array[i] [w-2] && main_array[i+1][w-2]) && !(main_array[i][w-2+1] && main_array[i+1][w-2+1]))) return false; } } return true; } } |
它的基本作用是从一个空矩阵开始(其大小适合其下一个要给出矩阵的状态的状态),然后从左上角开始,将有效宽度和高度交替增加1,然后检查是否到现在为止,矩阵的下一个状态对应于给定状态。如果不是,它将跳过矩阵的其余部分。然后,如果找到其下一个状态与给定状态相同的矩阵,则它将计数器加1。
此代码适用于小型矩阵(小于40的单元数),但是对于大型矩阵需要花费大量时间。矩阵的最大宽度可以为
我知道我必须在这里使用记忆(做数千次
有许多可能的矩阵会产生给定的下一个状态。 如果给出了下一个状态矩阵
被填充,然后用以下方式用值
1 2 3 4 5 6 7 8 | if n[x][y] == 1: if s == 0 than m[x][y] = 1 if s == 1 than m[x][y] = 0 if s > 1 than m[x][y] can't be filled if n[x][y] == 0: if s == 0 than m[x][y] = 0 if s == 1 than m[x][y] = 1 if s > 1 than m[x][y] = 0 or 1 |
看起来
由于身高受到较小值的限制,因此我建议先用可能的方法填充最后一列
值,则向后传递列,填充最后一列元素,然后由上方检查填充元素。
Python实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import numpy from itertools import product num_results = 0 def fill_xy(m, s, x, y): if y < 0: fill_x_last(m, s, x-1) return _sum = s[x+1, y] + s[x+1, y+1] + s[x, y+1] if m[x, y] == 1: if _sum == 0: s[x, y] = 1 elif _sum == 1: s[x, y] = 0 else: return else: if _sum == 0: s[x, y] = 0 elif _sum == 1: s[x, y] = 1 else: s[x, y] = 0 fill_xy(m, s, x, y-1) s[x, y] = 1 fill_xy(m, s, x, y-1) def fill_x_last(m, s, x): global num_results if x < 0: print s num_results += 1 else: s[x, s.shape[1]-1] = 0 fill_xy(m, s, x, s.shape[1]-2) s[x, s.shape[1]-1] = 1 fill_xy(m, s, x, s.shape[1]-2) def solve(m): global num_results height = m.shape[1]+1 s = numpy.zeros((m.shape[0]+1, height), dtype=numpy.uint8) for p in product((0, 1), repeat=height): s[-1, :] = p fill_x_last(m, s, s.shape[0]-2) print num_results solve(numpy.array([[0, 1, 1], [0, 1, 0]], dtype=numpy.uint8)) |