刚才看了http://topic.csdn.net/u/20120307/10/9cec9f97-a27f-41d5-a6f1-559f81ad6797.html?6310,鄙人这里也有一道题,特此分享。我们有一个正方形的矩阵,里面的元素不是1就是0。我们要做的工作就是统计里面全部为1的小正方形(大小至少是2x2的)的个数。比如说:
101111
001111
111111
001111
101101
111001对于这个矩阵我们可以得到结果:
2 10
3 4
4 1  意思是里面有2x2的且全部元素为1的矩阵10个,3x3的且全部元素为1的矩阵4个,4x4的且全部元素为1的矩阵1个。这个题目网上有,大家自己想想吧,很有意思的。

解决方案 »

  1.   

    常规算法,遍历矩阵判断元素的和是否满足n*n,如果满足,则说明n*n的矩阵的元素都是1
    思路,来看一下一个n*n(假设n为3)的子矩阵的情况
    1 0 0 1
    1 1 0 1
    1 1 n 1
    0 1 1 n+1
    那么,(0,0)到(n,n)是否满足都是1的情况,就是该矩阵的和是否=n*n,比如一个2x2矩阵,全部元素都是1,则所有元素的和为2*2=4,一个3x3矩阵,如果全部元素都是1,则所有元素的和为3*3=9,等等
    那么,从某个点开始求一个n*n矩阵的和很简单,这里采用了取巧的方法,当从n*n矩阵变到(n+1)*(n+1)矩阵的时候,实际上矩阵的和就是在n*n矩阵的和的基础上,加上n+1所在的行和列的元素的和,这样,我们就不用每次都从头开始计算一次矩阵的和,只需要循环不断的增加n,并加上n所在的行和列的值求总和,然后判断和是否满足n*n就可以了
    import java.util.*;
    public class Test {
        public static void main(String[] args) throws Throwable {
            int[][] matrix = {
                {1,0,1,1,1,1},
                {0,0,1,1,1,1},
                {1,1,1,1,1,1},
                {0,0,1,1,1,1},
                {1,0,1,1,0,1},
                {1,1,1,0,0,1}
            };
            
            countMatrix(matrix);
        }    public static void countMatrix(int[][] matrix) {
            if (matrix==null || matrix.length==0 || matrix[0].length==0) {
                System.out.println("no matrix.");
                return;
            }        List<Integer> list = new ArrayList<Integer>(); //用集合保存每种矩阵的个数
            for (int i=0; i<matrix.length; i++) {
                list.add(0); //list(0)保存1x1矩阵的个数,list(1)保存2x2矩阵个数,等等
            }        int sum = 0;
            for (int i=0; i<matrix.length; i++) {
                for (int j=0; j<matrix[i].length; j++) {
                    sum = 0; //如果不统计1x1矩阵,把这里初始化为 sum = matrix[i][j];
                             //然后把下面的for循环改为从k=1开始就可以了
                    for (int k=0; i+k<matrix.length && j+k<matrix[i].length; k++) {
                    //从某个(i,j)点开始,不断地寻找k*k矩阵,k循环增大
                        if (k==0) {
                            sum += matrix[i][j]; //计算矩阵起点的值
                        } else {
                            for (int m=0; m<k; m++) {
                                sum += matrix[i+m][j+k]; //计算k元素所在的行和列的值
                                sum += matrix[i+k][j+m]; //这里不包含k元素本身
                            }
                            sum += matrix[i+k][j+k]; //计算k元素本身的值
                        }
                        if (sum == (k+1)*(k+1)) { //判断矩阵元素的和是否满足n*n
                            list.set(k, list.get(k)+1); //把结果保存到集合中
                        }
                    }
                }
            }        for (int i=0; i<list.size(); i++) {
                System.out.printf("matrix:%dx%d, count:%d\n", i+1, i+1, list.get(i));
            }
        }
    }
      

  2.   


    你的算法是四次方级的
    你可以跑一下下面这个数据试试 看看能不能在0.01秒内出结果
    http://115.com/file/c2ls6epi
    #input.txt
      

  3.   


    修改了一下程序,思路不变,采用boolean类型,判断n*n的子矩阵中,只要有一个元素为0,就不符合条件,退出下一层矩阵(n+1)*(n+1)的循环修改的程序跑了一遍你的测试数据input.txt,忽略文件读入的时间,算法上所花时间我的机器上为31毫秒
    import java.util.*;
    public class Test {
        public static void main(String[] args) throws Throwable {
    /*
            char[][] matrix = {
                {'1','0','1','1','1','1'},
                {'0','0','1','1','1','1'},
                {'1','1','1','1','1','1'},
                {'0','0','1','1','1','1'},
                {'1','0','1','1','0','1'},
                {'1','1','1','0','0','1'}
            };
    */
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("f:\\input.txt")));
            List<char[]> data = new ArrayList<char[]>();
            for (String buf=br.readLine(); buf!=null; buf=br.readLine()) {
                data.add(buf.toCharArray());
            }
            char[][] matrix = new char[data.size()][];
            for (int i=0; i<matrix.length; i++) {
                matrix[i] = data.get(i);
            }
         
            long t1 = System.currentTimeMillis();
            countMatrix(matrix);
            long t2 = System.currentTimeMillis();
            System.out.printf("time=%dms\n", t2-t1);
        }    public static void countMatrix(char[][] matrix) {
            if (matrix==null || matrix.length==0 || matrix[0].length==0) {
                System.out.println("no matrix.");
                return;
            }        List<int[]> list = new ArrayList<int[]>();
            boolean f = true;
            for (int i=0; i<matrix.length; i++) {
                for (int j=0; j<matrix[i].length; j++) {
                    if (matrix[i][j] == '0') continue;
                    f = true;
                    for (int k=1; i+k<matrix.length && j+k<matrix[i].length; k++) {
                        for (int m=0; m<k; m++) {
                            f &= (matrix[i+m][j+k]=='1'); 
                            if (!f) break;                        f &= (matrix[i+k][j+m]=='1'); 
                            if (!f) break;
                        }
                        if (!f) break;
                        f &= (matrix[i+k][j+k]=='1'); 
                        if (!f) break;                    if (list.size() < k) {
                            list.add(new int[]{k+1, 1});
                        } else {
                            list.get(k-1)[1]++;
                        }
                    }
                }
            }        for (int[] m : list) {
                System.out.printf("matrix:%dx%d, count:%d\n", m[0], m[0], m[1]);
            }
        }
    }
      

  4.   

    规律是可以找到一些,不过还没空整理,有时间的时候再来想想。
    先把整理的一部分贴出来来看一个全部元素都是1的6X6的矩阵
    1 1 1 1 1 1
    1 1 1 1 1 1
    1 1 1 1 1 1
    1 1 1 1 1 1
    1 1 1 1 1 1
    1 1 1 1 1 1
    那么元素都是1的子矩阵的情况有

    1X1:(6-1+1)^2=361 1
    1 1
    2X2:(6-2+1)^2=251 1 1
    1 1 1
    1 1 1
    3X3:(6-3+1)^2=161 1 1 1
    1 1 1 1
    1 1 1 1
    1 1 1 1
    4X4:(6-4+1)^2=91 1 1 1 1
    1 1 1 1 1
    1 1 1 1 1
    1 1 1 1 1
    1 1 1 1 1
    5X5:(6-5+1)^2=4
    也就是说,元素全是1的n*n矩阵,k*k子矩阵的个数有 (n-k+1)^2接下来看看某个元素(只有1个元素)为0时,会造成多少个子矩阵不成立
    先看一个特殊值 c= n/2 + n%2,n=6时,c=3,也就是中间位置
    对于i行j列元素为0(先不看j列),当i>=k && i<=n-k,最多影响 min(c,k) 个 k*k矩阵,当i从中间往外扩展,依次减少1个,同样的,j列也如此,所以总共影响的的个数为 i行影响的个数*j列影响的个数
    i行j列影响的个数可以总结如下:1X1: [1, 1, 1, 1, 1, 1] 不管i行j列位置如何,都只影响1个矩阵
    2X2: [1, 2, 2, 2, 2, 1] 0行2列影响的个数有 p[i]*p[j]=1*2=2个 1行3列有 p[1]*p[3]=2*2=4个
    3X3: [1, 2, 3, 3, 2, 1] 2行3列影响的个数有 p[2]*p[3]=3*3=9个 1行3列有 p[1]*p[3]=2*3=6个
    4X4: [1, 2, 3, 3, 2, 1] 例子同上
    5X5: [1, 2, 2, 2, 2, 1] 例子同上
    6X6: [1, 1, 1, 1, 1, 1] 例子同上从表中,我们还发现,2X2和5X5的影响相同,3X3和4X4的影响相同,也就是从中间位置 c 往外扩展的情况是一样的再看多个元素同时为0的情况,此时会有重复的情况,目前还没找到重复的规律,以后有空再继续思考了,找到规律后再补充了。
      

  5.   

    http://www.weiyulan.tk/?p=602我的算法的源码
    算法在注释中