Official

C - Matrix Reducing Editorial by en_translator


Instead of deleting rows and columns one by one as in the original Problem Statement, we may consider that we do the following exactly once: “choose some of (possibly \(0\)) rows and columns of the initial \(A\) and remove the chosen rows and columns at once.” For example, for the following \(A\) given in Sample Input 1,

1 2 3 4 5 
6 7 8 9 10 
11 12 13 14 15 
16 17 18 19 20 

we may choose the \(1\)-st row, \(3\)-rd row, \(2\)-nd column, and \(5\)-th column and remove them at once to make it equal the following \(B\) given in Sample Input 1:

6 8 9
16 18 19

In order to determine if we can make \(A\) equal \(B\) by the operations, it is sufficient to actually try all \(2^{H_1}\) ways to choose “whether to remove each of \(H_1\) rows” all \(2^{W_1}\) ways to choose “whether to remove each of \(W_1\) columns” (for a total of \(2^{(H_1+W_1)}\) ways), and check if any of them makes \(A\) equals \(B\).

In order to enumerate all the \(2^{(H_1+W_1)}\) ways to choose rows and columns, bit brute-forcing is a concise approach, which we describe below: Represent each of “the ways to choose whether to remove each of the \(H_1\) rows” by a \(H_1\)-digit binary non-negative integer \(X\) satisfying:

for \(i = 0, 1, 2, \ldots, H_1-1\),

  • If the \(i\)-th row is removed, the \(i\)-th digit from the bottom of \(X\) is \(1\);
  • If the \(i\)-th row is not removed, the \(i\)-th digit from the bottom of \(X\) is \(0\);

For example, the choice of removing the \(1\)-st and \(3\)-rd rows out of \(5\) rows can be represented by an integer \(00101\) written in base \(2\). This way, the \(2^{H_1}\) ways to choose rows can be represented by \(000\cdots 00, 000\cdots 01, \ldots, 111\cdots 11\) in base \(2\), or by \(0, 1, \ldots, 2^{H_1}-1\) in base \(10\). Similarly, “the ways to choose whether to remove each of the \(W_1\) columns” can be represented by \(0, 1, \ldots, 2^{W_1}-1\).

Therefore, we can brute force all the combinations of the ways of choosing rows and columns with a doubly nested loop of which one scans the way to choose rows, \(0, 1, \ldots, 2^{H_1}-1\), and the other scans the ways to choose columns, \(0, 1, \ldots, 2^{W_1}-1\).

The following is a sample code in C++.

#include <iostream>
#include <vector>
using namespace std;

int main(void)
{
  int h1, h2, w1, w2;
  int a[15][15], b[15][15];
  
  cin >> h1 >> w1;
  for(int i = 1; i <= h1; i++) for(int j = 1; j <= w1; j++) cin >> a[i][j];
  cin >> h2 >> w2;
  for(int i = 1; i <= h2; i++) for(int j = 1; j <= w2; j++) cin >> b[i][j];

  for(int i = 0; i < (1<<h1); i++){
    for(int j = 0; j < (1<<w1); j++){
      
      vector<int> hvec, wvec;
      for(int k = 1; k <= h1; k++) if((i & (1<<(k-1))) == 0) hvec.push_back(k);
      for(int k = 1; k <= w1; k++) if((j & (1<<(k-1))) == 0) wvec.push_back(k);
      if(hvec.size() != h2 || wvec.size() != w2) continue;
     
      bool match = true;
      for(int k = 1; k <= h2; k++){
        for(int l = 1; l <= w2; l++){
          if(a[hvec[k-1]][wvec[l-1]] != b[k][l]){
            match = false;
            break;
          }
        }
      }
      if(match){
        cout << "Yes" << endl;
        return 0;
      }
       
    }
  }
  cout << "No" << endl;

  return 0;
}

posted:
last update: