#include <bits/stdc++.h>
using namespace std;
#define ROW_1 4
#define COL_1 4
#define ROW_2 4
#define COL_2 4
void print(string display, vector<vector<int> > matrix,
int start_row, int start_column, int end_row,
int end_column)
{
cout << endl << display << " =>" << endl;
for (int i = start_row; i <= end_row; i++) {
for (int j = start_column; j <= end_column; j++) {
cout << setw(10);
cout << matrix[i][j];
}
cout << endl;
}
cout << endl;
return;
}
vector<vector<int> >
add_matrix(vector<vector<int> > matrix_A,
vector<vector<int> > matrix_B, int split_index,
int multiplier = 1)
{
for (auto i = 0; i < split_index; i++)
for (auto j = 0; j < split_index; j++)
matrix_A[i][j]
= matrix_A[i][j]
+ (multiplier * matrix_B[i][j]);
return matrix_A;
}
vector<vector<int> >
multiply_matrix(vector<vector<int> > matrix_A,
vector<vector<int> > matrix_B)
{
int col_1 = matrix_A[0].size();
int row_1 = matrix_A.size();
int col_2 = matrix_B[0].size();
int row_2 = matrix_B.size();
if (col_1 != row_2) {
cout << "\nError: The number of columns in Matrix "
"A must be equal to the number of rows in "
"Matrix B\n";
return {};
}
vector<int> result_matrix_row(col_2, 0);
vector<vector<int> > result_matrix(row_1,
result_matrix_row);
if (col_1 == 1)
result_matrix[0][0]
= matrix_A[0][0] * matrix_B[0][0];
else {
int split_index = col_1 / 2;
vector<int> row_vector(split_index, 0);
vector<vector<int> > a00(split_index, row_vector);
vector<vector<int> > a01(split_index, row_vector);
vector<vector<int> > a10(split_index, row_vector);
vector<vector<int> > a11(split_index, row_vector);
vector<vector<int> > b00(split_index, row_vector);
vector<vector<int> > b01(split_index, row_vector);
vector<vector<int> > b10(split_index, row_vector);
vector<vector<int> > b11(split_index, row_vector);
for (auto i = 0; i < split_index; i++)
for (auto j = 0; j < split_index; j++) {
a00[i][j] = matrix_A[i][j];
a01[i][j] = matrix_A[i][j + split_index];
a10[i][j] = matrix_A[split_index + i][j];
a11[i][j] = matrix_A[i + split_index]
[j + split_index];
b00[i][j] = matrix_B[i][j];
b01[i][j] = matrix_B[i][j + split_index];
b10[i][j] = matrix_B[split_index + i][j];
b11[i][j] = matrix_B[i + split_index]
[j + split_index];
}
vector<vector<int> > p(multiply_matrix(
a00, add_matrix(b01, b11, split_index, -1)));
vector<vector<int> > q(multiply_matrix(
add_matrix(a00, a01, split_index), b11));
vector<vector<int> > r(multiply_matrix(
add_matrix(a10, a11, split_index), b00));
vector<vector<int> > s(multiply_matrix(
a11, add_matrix(b10, b00, split_index, -1)));
vector<vector<int> > t(multiply_matrix(
add_matrix(a00, a11, split_index),
add_matrix(b00, b11, split_index)));
vector<vector<int> > u(multiply_matrix(
add_matrix(a01, a11, split_index, -1),
add_matrix(b10, b11, split_index)));
vector<vector<int> > v(multiply_matrix(
add_matrix(a00, a10, split_index, -1),
add_matrix(b00, b01, split_index)));
vector<vector<int> > result_matrix_00(add_matrix(
add_matrix(add_matrix(t, s, split_index), u,
split_index),
q, split_index, -1));
vector<vector<int> > result_matrix_01(
add_matrix(p, q, split_index));
vector<vector<int> > result_matrix_10(
add_matrix(r, s, split_index));
vector<vector<int> > result_matrix_11(add_matrix(
add_matrix(add_matrix(t, p, split_index), r,
split_index, -1),
v, split_index, -1));
for (auto i = 0; i < split_index; i++)
for (auto j = 0; j < split_index; j++) {
result_matrix[i][j]
= result_matrix_00[i][j];
result_matrix[i][j + split_index]
= result_matrix_01[i][j];
result_matrix[split_index + i][j]
= result_matrix_10[i][j];
result_matrix[i + split_index]
[j + split_index]
= result_matrix_11[i][j];
}
a00.clear();
a01.clear();
a10.clear();
a11.clear();
b00.clear();
b01.clear();
b10.clear();
b11.clear();
p.clear();
q.clear();
r.clear();
s.clear();
t.clear();
u.clear();
v.clear();
result_matrix_00.clear();
result_matrix_01.clear();
result_matrix_10.clear();
result_matrix_11.clear();
}
return result_matrix;
}
int main()
{
vector<vector<int> > matrix_A = { { 1, 1, 1, 1 },
{ 2, 2, 2, 2 },
{ 3, 3, 3, 3 },
{ 2, 2, 2, 2 } };
print("Array A", matrix_A, 0, 0, ROW_1 - 1, COL_1 - 1);
vector<vector<int> > matrix_B = { { 1, 1, 1, 1 },
{ 2, 2, 2, 2 },
{ 3, 3, 3, 3 },
{ 2, 2, 2, 2 } };
print("Array B", matrix_B, 0, 0, ROW_2 - 1, COL_2 - 1);
vector<vector<int> > result_matrix(
multiply_matrix(matrix_A, matrix_B));
print("Result Array", result_matrix, 0, 0, ROW_1 - 1,
COL_2 - 1);
}
// Time Complexity: T(N) = 7T(N/2) + O(N^2) => O(N^Log7)
// which is approximately O(N^2.8074) Code Contributed By:
// lucasletum
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CiAKI2RlZmluZSBST1dfMSA0CiNkZWZpbmUgQ09MXzEgNAogCiNkZWZpbmUgUk9XXzIgNAojZGVmaW5lIENPTF8yIDQKIAp2b2lkIHByaW50KHN0cmluZyBkaXNwbGF5LCB2ZWN0b3I8dmVjdG9yPGludD4gPiBtYXRyaXgsCiAgICAgICAgICAgaW50IHN0YXJ0X3JvdywgaW50IHN0YXJ0X2NvbHVtbiwgaW50IGVuZF9yb3csCiAgICAgICAgICAgaW50IGVuZF9jb2x1bW4pCnsKICAgIGNvdXQgPDwgZW5kbCA8PCBkaXNwbGF5IDw8ICIgPT4iIDw8IGVuZGw7CiAgICBmb3IgKGludCBpID0gc3RhcnRfcm93OyBpIDw9IGVuZF9yb3c7IGkrKykgewogICAgICAgIGZvciAoaW50IGogPSBzdGFydF9jb2x1bW47IGogPD0gZW5kX2NvbHVtbjsgaisrKSB7CiAgICAgICAgICAgIGNvdXQgPDwgc2V0dygxMCk7CiAgICAgICAgICAgIGNvdXQgPDwgbWF0cml4W2ldW2pdOwogICAgICAgIH0KICAgICAgICBjb3V0IDw8IGVuZGw7CiAgICB9CiAgICBjb3V0IDw8IGVuZGw7CiAgICByZXR1cm47Cn0KIAp2ZWN0b3I8dmVjdG9yPGludD4gPgphZGRfbWF0cml4KHZlY3Rvcjx2ZWN0b3I8aW50PiA+IG1hdHJpeF9BLAogICAgICAgICAgIHZlY3Rvcjx2ZWN0b3I8aW50PiA+IG1hdHJpeF9CLCBpbnQgc3BsaXRfaW5kZXgsCiAgICAgICAgICAgaW50IG11bHRpcGxpZXIgPSAxKQp7CiAgICBmb3IgKGF1dG8gaSA9IDA7IGkgPCBzcGxpdF9pbmRleDsgaSsrKQogICAgICAgIGZvciAoYXV0byBqID0gMDsgaiA8IHNwbGl0X2luZGV4OyBqKyspCiAgICAgICAgICAgIG1hdHJpeF9BW2ldW2pdCiAgICAgICAgICAgICAgICA9IG1hdHJpeF9BW2ldW2pdCiAgICAgICAgICAgICAgICAgICsgKG11bHRpcGxpZXIgKiBtYXRyaXhfQltpXVtqXSk7CiAgICByZXR1cm4gbWF0cml4X0E7Cn0KIAp2ZWN0b3I8dmVjdG9yPGludD4gPgptdWx0aXBseV9tYXRyaXgodmVjdG9yPHZlY3RvcjxpbnQ+ID4gbWF0cml4X0EsCiAgICAgICAgICAgICAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiBtYXRyaXhfQikKewogICAgaW50IGNvbF8xID0gbWF0cml4X0FbMF0uc2l6ZSgpOwogICAgaW50IHJvd18xID0gbWF0cml4X0Euc2l6ZSgpOwogICAgaW50IGNvbF8yID0gbWF0cml4X0JbMF0uc2l6ZSgpOwogICAgaW50IHJvd18yID0gbWF0cml4X0Iuc2l6ZSgpOwogCiAgICBpZiAoY29sXzEgIT0gcm93XzIpIHsKICAgICAgICBjb3V0IDw8ICJcbkVycm9yOiBUaGUgbnVtYmVyIG9mIGNvbHVtbnMgaW4gTWF0cml4ICIKICAgICAgICAgICAgICAgICJBICBtdXN0IGJlIGVxdWFsIHRvIHRoZSBudW1iZXIgb2Ygcm93cyBpbiAiCiAgICAgICAgICAgICAgICAiTWF0cml4IEJcbiI7CiAgICAgICAgcmV0dXJuIHt9OwogICAgfQogCiAgICB2ZWN0b3I8aW50PiByZXN1bHRfbWF0cml4X3Jvdyhjb2xfMiwgMCk7CiAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiByZXN1bHRfbWF0cml4KHJvd18xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRfbWF0cml4X3Jvdyk7CiAKICAgIGlmIChjb2xfMSA9PSAxKQogICAgICAgIHJlc3VsdF9tYXRyaXhbMF1bMF0KICAgICAgICAgICAgPSBtYXRyaXhfQVswXVswXSAqIG1hdHJpeF9CWzBdWzBdOwogICAgZWxzZSB7CiAgICAgICAgaW50IHNwbGl0X2luZGV4ID0gY29sXzEgLyAyOwogCiAgICAgICAgdmVjdG9yPGludD4gcm93X3ZlY3RvcihzcGxpdF9pbmRleCwgMCk7CiAKICAgICAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiBhMDAoc3BsaXRfaW5kZXgsIHJvd192ZWN0b3IpOwogICAgICAgIHZlY3Rvcjx2ZWN0b3I8aW50PiA+IGEwMShzcGxpdF9pbmRleCwgcm93X3ZlY3Rvcik7CiAgICAgICAgdmVjdG9yPHZlY3RvcjxpbnQ+ID4gYTEwKHNwbGl0X2luZGV4LCByb3dfdmVjdG9yKTsKICAgICAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiBhMTEoc3BsaXRfaW5kZXgsIHJvd192ZWN0b3IpOwogICAgICAgIHZlY3Rvcjx2ZWN0b3I8aW50PiA+IGIwMChzcGxpdF9pbmRleCwgcm93X3ZlY3Rvcik7CiAgICAgICAgdmVjdG9yPHZlY3RvcjxpbnQ+ID4gYjAxKHNwbGl0X2luZGV4LCByb3dfdmVjdG9yKTsKICAgICAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiBiMTAoc3BsaXRfaW5kZXgsIHJvd192ZWN0b3IpOwogICAgICAgIHZlY3Rvcjx2ZWN0b3I8aW50PiA+IGIxMShzcGxpdF9pbmRleCwgcm93X3ZlY3Rvcik7CiAKICAgICAgICBmb3IgKGF1dG8gaSA9IDA7IGkgPCBzcGxpdF9pbmRleDsgaSsrKQogICAgICAgICAgICBmb3IgKGF1dG8gaiA9IDA7IGogPCBzcGxpdF9pbmRleDsgaisrKSB7CiAgICAgICAgICAgICAgICBhMDBbaV1bal0gPSBtYXRyaXhfQVtpXVtqXTsKICAgICAgICAgICAgICAgIGEwMVtpXVtqXSA9IG1hdHJpeF9BW2ldW2ogKyBzcGxpdF9pbmRleF07CiAgICAgICAgICAgICAgICBhMTBbaV1bal0gPSBtYXRyaXhfQVtzcGxpdF9pbmRleCArIGldW2pdOwogICAgICAgICAgICAgICAgYTExW2ldW2pdID0gbWF0cml4X0FbaSArIHNwbGl0X2luZGV4XQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbaiArIHNwbGl0X2luZGV4XTsKICAgICAgICAgICAgICAgIGIwMFtpXVtqXSA9IG1hdHJpeF9CW2ldW2pdOwogICAgICAgICAgICAgICAgYjAxW2ldW2pdID0gbWF0cml4X0JbaV1baiArIHNwbGl0X2luZGV4XTsKICAgICAgICAgICAgICAgIGIxMFtpXVtqXSA9IG1hdHJpeF9CW3NwbGl0X2luZGV4ICsgaV1bal07CiAgICAgICAgICAgICAgICBiMTFbaV1bal0gPSBtYXRyaXhfQltpICsgc3BsaXRfaW5kZXhdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtqICsgc3BsaXRfaW5kZXhdOwogICAgICAgICAgICB9CiAKICAgICAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiBwKG11bHRpcGx5X21hdHJpeCgKICAgICAgICAgICAgYTAwLCBhZGRfbWF0cml4KGIwMSwgYjExLCBzcGxpdF9pbmRleCwgLTEpKSk7CiAgICAgICAgdmVjdG9yPHZlY3RvcjxpbnQ+ID4gcShtdWx0aXBseV9tYXRyaXgoCiAgICAgICAgICAgIGFkZF9tYXRyaXgoYTAwLCBhMDEsIHNwbGl0X2luZGV4KSwgYjExKSk7CiAgICAgICAgdmVjdG9yPHZlY3RvcjxpbnQ+ID4gcihtdWx0aXBseV9tYXRyaXgoCiAgICAgICAgICAgIGFkZF9tYXRyaXgoYTEwLCBhMTEsIHNwbGl0X2luZGV4KSwgYjAwKSk7CiAgICAgICAgdmVjdG9yPHZlY3RvcjxpbnQ+ID4gcyhtdWx0aXBseV9tYXRyaXgoCiAgICAgICAgICAgIGExMSwgYWRkX21hdHJpeChiMTAsIGIwMCwgc3BsaXRfaW5kZXgsIC0xKSkpOwogICAgICAgIHZlY3Rvcjx2ZWN0b3I8aW50PiA+IHQobXVsdGlwbHlfbWF0cml4KAogICAgICAgICAgICBhZGRfbWF0cml4KGEwMCwgYTExLCBzcGxpdF9pbmRleCksCiAgICAgICAgICAgIGFkZF9tYXRyaXgoYjAwLCBiMTEsIHNwbGl0X2luZGV4KSkpOwogICAgICAgIHZlY3Rvcjx2ZWN0b3I8aW50PiA+IHUobXVsdGlwbHlfbWF0cml4KAogICAgICAgICAgICBhZGRfbWF0cml4KGEwMSwgYTExLCBzcGxpdF9pbmRleCwgLTEpLAogICAgICAgICAgICBhZGRfbWF0cml4KGIxMCwgYjExLCBzcGxpdF9pbmRleCkpKTsKICAgICAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiB2KG11bHRpcGx5X21hdHJpeCgKICAgICAgICAgICAgYWRkX21hdHJpeChhMDAsIGExMCwgc3BsaXRfaW5kZXgsIC0xKSwKICAgICAgICAgICAgYWRkX21hdHJpeChiMDAsIGIwMSwgc3BsaXRfaW5kZXgpKSk7CiAKICAgICAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiByZXN1bHRfbWF0cml4XzAwKGFkZF9tYXRyaXgoCiAgICAgICAgICAgIGFkZF9tYXRyaXgoYWRkX21hdHJpeCh0LCBzLCBzcGxpdF9pbmRleCksIHUsCiAgICAgICAgICAgICAgICAgICAgICAgc3BsaXRfaW5kZXgpLAogICAgICAgICAgICBxLCBzcGxpdF9pbmRleCwgLTEpKTsKICAgICAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiByZXN1bHRfbWF0cml4XzAxKAogICAgICAgICAgICBhZGRfbWF0cml4KHAsIHEsIHNwbGl0X2luZGV4KSk7CiAgICAgICAgdmVjdG9yPHZlY3RvcjxpbnQ+ID4gcmVzdWx0X21hdHJpeF8xMCgKICAgICAgICAgICAgYWRkX21hdHJpeChyLCBzLCBzcGxpdF9pbmRleCkpOwogICAgICAgIHZlY3Rvcjx2ZWN0b3I8aW50PiA+IHJlc3VsdF9tYXRyaXhfMTEoYWRkX21hdHJpeCgKICAgICAgICAgICAgYWRkX21hdHJpeChhZGRfbWF0cml4KHQsIHAsIHNwbGl0X2luZGV4KSwgciwKICAgICAgICAgICAgICAgICAgICAgICBzcGxpdF9pbmRleCwgLTEpLAogICAgICAgICAgICB2LCBzcGxpdF9pbmRleCwgLTEpKTsKIAogICAgICAgIGZvciAoYXV0byBpID0gMDsgaSA8IHNwbGl0X2luZGV4OyBpKyspCiAgICAgICAgICAgIGZvciAoYXV0byBqID0gMDsgaiA8IHNwbGl0X2luZGV4OyBqKyspIHsKICAgICAgICAgICAgICAgIHJlc3VsdF9tYXRyaXhbaV1bal0KICAgICAgICAgICAgICAgICAgICA9IHJlc3VsdF9tYXRyaXhfMDBbaV1bal07CiAgICAgICAgICAgICAgICByZXN1bHRfbWF0cml4W2ldW2ogKyBzcGxpdF9pbmRleF0KICAgICAgICAgICAgICAgICAgICA9IHJlc3VsdF9tYXRyaXhfMDFbaV1bal07CiAgICAgICAgICAgICAgICByZXN1bHRfbWF0cml4W3NwbGl0X2luZGV4ICsgaV1bal0KICAgICAgICAgICAgICAgICAgICA9IHJlc3VsdF9tYXRyaXhfMTBbaV1bal07CiAgICAgICAgICAgICAgICByZXN1bHRfbWF0cml4W2kgKyBzcGxpdF9pbmRleF0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbaiArIHNwbGl0X2luZGV4XQogICAgICAgICAgICAgICAgICAgID0gcmVzdWx0X21hdHJpeF8xMVtpXVtqXTsKICAgICAgICAgICAgfQogCiAgICAgICAgYTAwLmNsZWFyKCk7CiAgICAgICAgYTAxLmNsZWFyKCk7CiAgICAgICAgYTEwLmNsZWFyKCk7CiAgICAgICAgYTExLmNsZWFyKCk7CiAgICAgICAgYjAwLmNsZWFyKCk7CiAgICAgICAgYjAxLmNsZWFyKCk7CiAgICAgICAgYjEwLmNsZWFyKCk7CiAgICAgICAgYjExLmNsZWFyKCk7CiAgICAgICAgcC5jbGVhcigpOwogICAgICAgIHEuY2xlYXIoKTsKICAgICAgICByLmNsZWFyKCk7CiAgICAgICAgcy5jbGVhcigpOwogICAgICAgIHQuY2xlYXIoKTsKICAgICAgICB1LmNsZWFyKCk7CiAgICAgICAgdi5jbGVhcigpOwogICAgICAgIHJlc3VsdF9tYXRyaXhfMDAuY2xlYXIoKTsKICAgICAgICByZXN1bHRfbWF0cml4XzAxLmNsZWFyKCk7CiAgICAgICAgcmVzdWx0X21hdHJpeF8xMC5jbGVhcigpOwogICAgICAgIHJlc3VsdF9tYXRyaXhfMTEuY2xlYXIoKTsKICAgIH0KICAgIHJldHVybiByZXN1bHRfbWF0cml4Owp9CiAKaW50IG1haW4oKQp7CiAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiBtYXRyaXhfQSA9IHsgeyAxLCAxLCAxLCAxIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyAyLCAyLCAyLCAyIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyAzLCAzLCAzLCAzIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyAyLCAyLCAyLCAyIH0gfTsKIAogICAgcHJpbnQoIkFycmF5IEEiLCBtYXRyaXhfQSwgMCwgMCwgUk9XXzEgLSAxLCBDT0xfMSAtIDEpOwogCiAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiBtYXRyaXhfQiA9IHsgeyAxLCAxLCAxLCAxIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyAyLCAyLCAyLCAyIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyAzLCAzLCAzLCAzIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyAyLCAyLCAyLCAyIH0gfTsKIAogICAgcHJpbnQoIkFycmF5IEIiLCBtYXRyaXhfQiwgMCwgMCwgUk9XXzIgLSAxLCBDT0xfMiAtIDEpOwogCiAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiByZXN1bHRfbWF0cml4KAogICAgICAgIG11bHRpcGx5X21hdHJpeChtYXRyaXhfQSwgbWF0cml4X0IpKTsKIAogICAgcHJpbnQoIlJlc3VsdCBBcnJheSIsIHJlc3VsdF9tYXRyaXgsIDAsIDAsIFJPV18xIC0gMSwKICAgICAgICAgIENPTF8yIC0gMSk7Cn0KIAovLyBUaW1lIENvbXBsZXhpdHk6IFQoTikgPSA3VChOLzIpICsgIE8oTl4yKSA9PiBPKE5eTG9nNykKLy8gd2hpY2ggaXMgYXBwcm94aW1hdGVseSBPKE5eMi44MDc0KSBDb2RlIENvbnRyaWJ1dGVkIEJ5OgovLyBsdWNhc2xldHVt