Minimum cost to convert 3 X 3 matrix into magic square

A Magic Square is a n x n matrix of distinct element from 1 to n2 where the sum of any row, column or diagonal is always equal to same number.
Consider a 3 X 3 matrix, s, of integers in the inclusive range [1, 9] . We can convert any digit, a, to any other digit, b, in the range [1, 9] at cost |a – b|.
Given s, convert it into a magic square at minimal cost by changing zero or more of its digits. The task is to find minimum cost.
Note: The resulting matrix must contain distinct integers in the inclusive range [1, 9].

Examples:

Input : mat[][] = { { 4, 9, 2 },
                    { 3, 5, 7 },
                    { 8, 1, 5 }};
Output : 1
Given matrix s is not a magic square. To convert
it into magic square we change the bottom right 
value, s[2][2], from 5 to 6 at a cost of | 5 - 6 |
= 1.

Input : mat[][] = { { 4, 8, 2 },
                    { 4, 5, 7 },
                    { 6, 1, 6 }};
Output : 4

The idea is to find all 3 X 3 magic squares and, for each one, compute the cost of changing mat into a known magic square. The result is the smallest of these costs.
We know that s will always be 3 X 3. There are 8 possible magic squares for 3 X 3 matrix.
There are two ways to approach this:
So, compute all 8 magic squares by examining all permutations of integers 1, 2, 3, ….., 9 and for each one, check if it forms a magic square if the permutation is inserted into the square starting from the upper left hand corner.

Below is C++ implementation of this approach:

#include <bits/stdc++.h>
using namespace std;

// Return if given vector denote the magic square or not.
bool is_magic_square(vector<int> v)
{
    int a[3][3];

    // Convert vector into 3 X 3 matrix
    for (int i = 0; i < 3; ++i) 
        for (int j = 0; j < 3; ++j) 
            a[i][j] = v[3 * i + j];       

    int s = 0;
    for (int j = 0; j < 3; ++j)
        s += a[0][j];

    // Checking if each row sum is same
    for (int i = 1; i <= 2; ++i) {
        int tmp = 0;
        for (int j = 0; j < 3; ++j)
            tmp += a[i][j];
        if (tmp != s)
            return 0;
    }

    // Checking if each column sum is same
    for (int j = 0; j < 3; ++j) {
        int tmp = 0;
        for (int i = 0; i < 3; ++i)
            tmp += a[i][j];
        if (tmp != s)
            return 0;
    }    

    // Checking if diagonal 1 sum is same
    int tmp = 0;
    for (int i = 0; i < 3; ++i)
        tmp += a[i][i];
    if (tmp != s)
        return 0;    

    // Checking if diagnol 2 sum is same
    tmp = 0;
    for (int i = 0; i < 3; ++i)
        tmp += a[2 - i][i];
    if (tmp != s)
        return 0;
    return 1;
}

// Generating all magic square
void find_magic_squares(vector<vector<int> >& magic_squares)
{
    vector<int> v(9);

    // Initialing the vector
    for (int i = 0; i < 9; ++i)
        v[i] = i + 1;

    // Producing all permutation of vector
    // and checking if it denote the magic square or not.
    do {
        if (is_magic_square(v)) {
            magic_squares.push_back(v);
        }
    } while (next_permutation(v.begin(), v.end()));
}

// Return sum of difference between each element of two vector
int diff(vector<int> a, vector<int> b)
{
    int res = 0;

    for (int i = 0; i < 9; ++i)
        res += abs(a[i] - b[i]);

    return res;
}

// Wrapper function
int wrapper(vector<int> v)
{
    int res = INT_MAX;
    vector<vector<int> > magic_squares;

    // generating all magic square
    find_magic_squares(magic_squares);

    for (int i = 0; i < magic_squares.size(); ++i) {

        // Finding the difference with each magic square
        // and assigning the minimum value.
        res = min(res, diff(v, magic_squares[i]));
    }
    return res;
}

// Driven Program
int main()
{
    // Taking matrix in vector in rowise to make 
    // calculation easy
    vector<int> v;
    v.push_back(4);
    v.push_back(9);
    v.push_back(2);

    v.push_back(3);
    v.push_back(5);
    v.push_back(7);

    v.push_back(8);
    v.push_back(1);
    v.push_back(5);

    cout << wrapper(v) << endl;

    return 0;
}

Output:

1

This article is contributed by Anuj Chauhan. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

GATE CS Corner    Company Wise Coding Practice

Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.

Recommended Posts:



0 Average Difficulty : 0/5.0
No votes yet.










Writing code in comment? Please use ide.geeksforgeeks.org, generate link and share the link here.