关于Java:如何使用记忆来计算大量矩阵

How to use memoization in counting a large number of matrices

我得到了一个程序,该程序需要我计算矩阵以前状态的数量。

给定的矩阵是布尔矩阵。我将对true使用1,对于false使用0来解释程序。

如果考虑以下四个单元,则矩阵中单元的下一个状态为1

  • 细胞本身
  • 正确的细胞
  • 下面的单元格
  • 下方和右侧的单元格,

在这4个单元中只有一个1,即在这4个单元中正好有3个0和正好有1个1

如果给定的矩阵(M)为:
1 1 0 0
0 0 0 1
0 0 1 0

然后,对于第一个单元格(M [0] [0]),要考虑的四个单元格分别为M [0] [0],M [0] [1],M [1] [0]和M [1] [1]。因此,第一个单元格的下一个状态是0,因为这4个单元格中有2个1

对于第二个像元(M [0] [1]),要考虑的四个像元是M [0] [1],M [0] [2],M [1] [1],M [1] [ 2]。因此,此单元格的下一个状态是1,因为在这四个单元格中只有1个1

这样,此矩阵(M)的下一个状态将是矩阵(N):

0 1 1
0 1 0

显然,下一个状态将比前一个状态少1行1列。因此,矩阵的给定状态可以具有许多先前的状态,例如,除了矩阵M之外,给定矩阵:

1 0 1 0
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的单元数),但是对于大型矩阵需要花费大量时间。矩阵的最大宽度可以为50,最大高度可以为9。因此,此代码不适用于该目的。

我知道我必须在这里使用记忆(做数千次c++只是不对!),但是我无法想象如何实现它。我以前使用动态编程编写过程序,但是不知道在这里使用它的地方。任何帮助,将不胜感激。


有许多可能的矩阵会产生给定的下一个状态。 如果给出了下一个状态矩阵N,并且部分填充了初始矩阵M,例如元素m[x][y+1], m[x+1][y]m[x+1][y+1]
被填充,然后用以下方式用值s = m[x][y+1] + m[x+1][y] + m[x+1][y+1]检查元素m[x][y]的可能性:

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

看起来N"过滤器"组合中的值为1,而N"过滤"组合中的值为0。

由于身高受到较小值的限制,因此我建议先用可能的方法填充最后一列
值,则向后传递列,填充最后一列元素,然后由上方检查填充元素。

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))