最大的子矩阵,等于1和0

时间:2012-12-04 07:51:47

标签: algorithm dynamic-programming

给定一个大小为mxn的矩阵,仅包含0和1。我需要找到最大的子矩阵,其中包含相同数量的1和0。蛮力方法是O(m^2*n^2)我们可以做得比这更好吗?
我尝试应用动态编程,但找不到任何最佳子结构。

我相信这个问题的类似的一维版本在这里讨论:
Space-efficient algorithm for finding the largest balanced subarray?
它有O(n)解决方案,使用一些额外的空间。

4 个答案:

答案 0 :(得分:5)

该算法假设我们搜索具有连续行和列的子矩阵,并且具有最大可能的高度和宽度乘积。

从以下预处理开始:

A = substitute_zero_with_minus_one(InputMatrix)
B = prefix_sum_for_each_column(A)
C = prefix_sum_for_each_row(B)

现在,对于每对行(i,j),请执行以下操作:

for each column k:
  d = C[k, j] - C[k, i]
  if h[d] not empty:
    if (k - h[d]) * (j - i) is greater than best result:
      update best result
  else:
    h[d] = k

时间复杂度为O(N 2 * M),额外空间为O(N * M)。

答案 1 :(得分:1)

我们假设m< n,我们可以有一个O(M * M * N)算法。 如果我们将所有0替换为-1,我们只需找到最大的子矩阵,其总和为0.

  1. 获取每一行中的段(i,j)之和,我们将它们定义为c1,c2, c3 ....,cn,我们可以通过算法对它运行O(n)算法 引用。
  2. 我们应该执行步骤1 M * M次以获得总和为0的最大子矩阵,因此复杂度为O(M * M * N)。

答案 2 :(得分:1)

我假设只使用连续的行\列形成子矩阵 原始矩阵(即通过删除第一个\最后一行或列)。

这样,矩阵可以表示为

Mat = {origin(row,col), rowCount, columnCount}

如果原始矩阵的维数为M x N,那么

rowCount =  M - row
columnCount = N - col
Mat = {origin(row,col), M - row, N - col}.

变量rowcol分别有MN个值,这意味着 有O(MxN)个这样的矩阵。

算法理念

  1. 队列
  2. 中的pop matrix (m, n)
  3. 测试。如果成功,输出矩阵
  4. 构建所有矩阵(m, n-1)(m-1, n)并放入队列
  5. 回到1。
  6. 现在有两点:

    • 缩小尺寸时,只有4个可能的矩阵(2个删除行,2个删除列)
    • 通过删除第一行和最后一列来构造子矩阵。您只需删除已删除的行\列的计数,这需要O(n)O(m)时间。这是动态编程步骤。

    这意味着复杂性为O(max(M,N)MN)

答案 3 :(得分:1)

我创建了一个演示搜索算法优化的小应用程序。如果您正在寻找,请告诉我。

注意:

  1. 该程序创建一个方阵
  2. 为了便于阅读,我正在使用集合来处理数据。我相信处理过载,但我只想指出原则。
  3. 这是:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    
    class Program
    {
        class Matrix
        {
            public int[][] JaggedInteger2DMatrix { get; set; }
    
            public List<MatrixCell> Cells { get; set; }
            public List<MatrixLine> Lines { get; set; }
    
            public int Width { get; set; }
            public int Height { get; set; }
    
            public Matrix(int size, int seed)
            {
                var r = new Random(seed);
                int[][] jaggedInteger2DMatrix = new int[size][];
                for (int i = 0; i < size; i++)
                {
                    jaggedInteger2DMatrix[i] = new int[size];
                    for (int j = 0; j < size; j++)
                    {
                        jaggedInteger2DMatrix[i][j] = r.Next(2);
                        //Console.Write(jaggedInteger2DMatrix[i][j]+" ");
                    }
                    //Console.Write("\r\n");
                }
                InitializeMatrix(jaggedInteger2DMatrix);
            }
    
            public Matrix(int[][] jaggedInteger2DMatrix)
            {
                InitializeMatrix(jaggedInteger2DMatrix);
            }
    
            private void InitializeMatrix(int[][] jaggedInteger2DMatrix)
            {
                JaggedInteger2DMatrix = jaggedInteger2DMatrix;
                Height = jaggedInteger2DMatrix.GetLength(0);
                Width = jaggedInteger2DMatrix[0].GetLength(0);
                Cells = new List<MatrixCell>();
                Lines = new List<MatrixLine>();
                int horizontalLineCounter = 0;
                MatrixCell matrixCell = null;
                foreach (var horizontalLine in jaggedInteger2DMatrix)
                {
                    int verticalLineCounter = 0;
                    foreach (var cell in horizontalLine)
                    {
                        matrixCell = new MatrixCell()
                        {
                            HorizontalLineIndex = horizontalLineCounter,
                            Value = cell,
                            VerticalLineIndex = verticalLineCounter
                        };
                        Cells.Add(matrixCell);
    
                        if (Lines.Where(line => line.LineType == Line.Vertical && line.LineIndex == verticalLineCounter).Count() == 0)
                        {
                            var line = new MatrixLine()
                            {
                                LineType = Line.Vertical,
                                LineIndex = verticalLineCounter
                            };
                            Lines.Add(line);
                        }
    
                        Lines.Where(line => line.LineType == Line.Vertical && line.LineIndex == verticalLineCounter).FirstOrDefault().Cells.Add(matrixCell);
    
                        if (Lines.Where(line => line.LineType == Line.Horizontal && line.LineIndex == horizontalLineCounter).Count() == 0)
                        {
                            var line = new MatrixLine()
                            {
                                LineType = Line.Horizontal,
                                LineIndex = horizontalLineCounter
                            };
                            Lines.Add(line);
                        }
    
                        Lines.Where(line => line.LineType == Line.Horizontal && line.LineIndex == horizontalLineCounter).FirstOrDefault().Cells.Add(matrixCell);
    
                        verticalLineCounter++;
                    }
                    horizontalLineCounter++;
                }
            }
    
        }
    
        class MatrixCell
        {
            public int Value { get; set; }
            public int VerticalLineIndex { get; set; }
            public int HorizontalLineIndex { get; set; }
        }
    
        class MatrixLine
        {
            public Line LineType { get; set; }
            public int LineIndex { get; set; }
            public List<MatrixCell> Cells { get; set; }
            public MatrixLine()
            {
                Cells = new List<MatrixCell>();
            }
        }
    
        enum Line
        {
            Horizontal,
            Vertical
        }
    
        private static void Search(Matrix matrix, bool optimizeCellCount, out IEnumerable<MatrixCell> optimizedSelection, out int iterations)
        {
            optimizedSelection = null;
    
            var count = 0;
            iterations = 0;
            for (int i = 0; i < matrix.Width; i++)
            {
                for (int j = 1; j <= matrix.Width; j++)
                {
                    var selectedVerticalLines = matrix.Lines.Where(line => line.LineType == Line.Vertical).Skip(i).Take(j);
                    for (int k = 0; k < matrix.Height; k++)
                    {
                        for (int l = 1; l <= matrix.Height; l++)
                        {
                            /**
                             * Here's where the search is optimized
                             **********************************************************************************************
                             */
                            if (optimizeCellCount)
                            {
                                //if the submatrix cell count is smaller than the current count, break the iteration
                                if (count > Math.Min(Math.Abs(matrix.Height - k), l) * Math.Min(Math.Abs(matrix.Height - i), j))
                                {
                                    continue;
                                }
                            }
                            /*
                             **********************************************************************************************
                             */
                            iterations++;
    
                            var selectedHorizontalLines = matrix.Lines.Where(line => line.LineType == Line.Horizontal).Skip(k).Take(l);
    
                            var horizontalCells = selectedHorizontalLines.Aggregate<MatrixLine, List<MatrixCell>>(new List<MatrixCell>(), (a, b) =>
                            {
                                a.AddRange(b.Cells);
                                return a;
                            });
                            var verticalCells = selectedVerticalLines.Aggregate<MatrixLine, List<MatrixCell>>(new List<MatrixCell>(), (a, b) =>
                            {
                                a.AddRange(b.Cells);
                                return a;
                            });
    
                            var cells = horizontalCells.Intersect(verticalCells);
                            if (cells.Count() > count)
                            {
                                var sum = cells.Sum(t => t.Value);
                                var cellsCount = cells.Count();
                                if (sum != 0)
                                {
                                    if (cellsCount / (double)sum == 2)
                                    {
                                        //match
                                        optimizedSelection = cells;
                                        count = cellsCount;
    
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    
        private static float GetLineCost(int width, int startPosition, int length)
        {
            float cost = 0;
            for (int i = startPosition; i < length; i++)
            {
                cost += Math.Min(Math.Abs(width - i), i + 1);
            }
            return cost;
        }
    
        static void Main(string[] args)
        {
            Matrix matrix = new Matrix(20, 1);
    
            bool optimizeCellCount = true;
    
            IEnumerable<MatrixCell> optimizedSelection;
            int iterations;
    
            var watch = new System.Diagnostics.Stopwatch();
    
            //optimized search
            watch.Start();
            Search(matrix, optimizeCellCount, out optimizedSelection, out iterations);
            watch.Stop();
            Console.WriteLine("Full Optimized Search");
            Console.WriteLine("position: [{0},{1}],[{2},{3}] size : {4} search time : {5} iterations: {6}",
                optimizedSelection.Min(cell => cell.VerticalLineIndex),
                optimizedSelection.Min(cell => cell.HorizontalLineIndex),
                optimizedSelection.Max(cell => cell.VerticalLineIndex),
                optimizedSelection.Max(cell => cell.HorizontalLineIndex),
                optimizedSelection.Count(),
                watch.Elapsed,
                iterations
                );
            watch.Reset();
    
            //no optimization
            watch.Start();
            Search(matrix, !optimizeCellCount, out optimizedSelection, out iterations);
            watch.Stop();
            Console.WriteLine("Non-Optimized Search");
            Console.WriteLine("position: [{0},{1}],[{2},{3}] size : {4} search time : {5} iterations: {6}",
                optimizedSelection.Min(cell => cell.VerticalLineIndex),
                optimizedSelection.Min(cell => cell.HorizontalLineIndex),
                optimizedSelection.Max(cell => cell.VerticalLineIndex),
                optimizedSelection.Max(cell => cell.HorizontalLineIndex),
                optimizedSelection.Count(),
                watch.Elapsed,
                iterations
                );
            watch.Reset();
    
            //Console Output:
            /***************************************************************************************
            *   Full Optimized Search
            *   position: [9,1],[18,19] size : 190 search time : 00:00:02.3963657 iterations: 19108
            *   Non-Optimized Search
            *   position: [9,1],[18,19] size : 190 search time : 00:00:05.8385388 iterations: 160000
            ****************************************************************************************/
    
        }
    }