草庐IT

java - 如何在计算大量矩阵时使用内存

coder 2024-03-08 原文

我得到了一个程序,它要求我计算一个矩阵的先前状态的数量。

给定的矩阵是一个 boolean 矩阵。我将使用 1 代表 true0 代表 false 来解释这个程序。

矩阵中一个单元格的下一个状态是 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。

我必须计算给定矩阵具有的先前状态的数量。

我写了下面的代码:

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("],","],\n").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] 被填充,然后检查元素 m[x][y] 的可能性 s = m[x][y+1] + m[x+1][y] + m[x+1][y+1],在某种程度上:

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 实现:

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

关于java - 如何在计算大量矩阵时使用内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41923054/

有关java - 如何在计算大量矩阵时使用内存的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  7. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  8. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  9. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  10. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

随机推荐