5

How to find out if it is possible to contruct a binary matrix with given row and column sums.

Input :

The first row of input contains two numbers 1≤m,n≤1000, the number of rows and columns of the matrix. The next row contains m numbers 0≤ri≤n – the sum of each row in the matrix. The third row contains n numbers 0≤cj≤m – the sum of each column in the matrix.

Output:

Output “YES” if there exists an m-by-n matrix A, with each element either being 0 or 1. Else "NO".

I tried reading about Tomography algorithms but could not figure out an answer as all the papers related to Tomography algorithm is very complicated.

Can someone please help me..

Sushil
  • 8,250
  • 3
  • 39
  • 71

1 Answers1

10

I've successfully implemented randomly generating such matrices for R using a modeling based on network flow. I intend to write up those ideas one day, but haven't found the time yet. Reasearching for that, I read in Randomization of Presence–absence Matrices: Comments and New Algorithms by Miklós and Podani:

The Havel-Hakimi theorem (Havel 1955, Hakimi 1962) states that there exists a matrix Xn,m of 0’s and 1’s with row totals a0=(a1, a2,… , an) and column totals b0=(b1, b2,… , bm) such that bibi+1 for every 0 < i < m if and only if another matrix Xn−1,m of 0’s and 1’s with row totals a1=(a2, a3,… , an) and column totals b1=(b1−1, b2−1,… ,ba1−1, ba1+1,… , bm) also exists.

I guess that should be the best method to recursively decide your question.

Phrased in my own words: Choose any row, remove it from the list of totals. Call that removed number k. Also subtract one from the k columns with larges sums. You obtain a description of a smaller matrix, and recurse. If at any point you don't have k columns with non-zero sums, then no such matrix can exist. Otherwise you can recursively build a matching matrix using the reverse process: take the matrix returned by the recursive call, then add one more row with k ones, placed in the columns from whose counts you originally subtracted one.

Implementation

bool satisfiable(std::vector<int> a, std::vector<int> b) {
  while (!a.empty()) {
    std::sort(b.begin(), b.end(), std::greater<int>());
    int k = a.back();
    a.pop_back();
    if (k > b.size()) return false;
    if (k == 0) continue;
    if (b[k - 1] == 0) return false;
    for (int i = 0; i < k; i++)
      b[i]--;
  }
  for (std::vector<int>::iterator i = b.begin(); i != b.end(); i++)
    if (*i != 0)
      return false;
  return true;
}
MvG
  • 57,380
  • 22
  • 148
  • 276
  • Thank you for your answer. I could partially understand your answer though it looks correct to me. So, can you please explain me with a small code in any language C, C++ or java. or with an example? – Sushil Jan 09 '14 at 05:27
  • 1
    Is there any optimal way of doing this?In each iteration the array of column is sorted ,if input is huge of the order 10^9 it takes a lot of time in each pass.Is there any way or property of binary matrix that can help us achieve this in o(n)?I scratched my head around this but I haven't found any way such.Thanks in advance for your help. – Hitesh May 30 '19 at 04:07
  • @Hitesh At the end of each iteration you get two ordered subsets. Then by using merge sort the new sorting can be performed in O(n), not O(nlogn). But global complexity remains huge – Damien May 30 '19 at 11:49
  • Hi All I have found the efficient algorithm for this problem on this thread https://stackoverflow.com/questions/56308347/arranging-the-number-1-in-a-2d-matrix – Hitesh Jun 03 '19 at 06:35