📜  将 3 X 3 矩阵转换为幻方的最低成本

📅  最后修改于: 2022-05-13 01:57:22.133000             🧑  作者: Mango

将 3 X 3 矩阵转换为幻方的最低成本

魔方是从 1 到 n2 的不同元素的 anxn 矩阵,其中任何行、列或对角线的总和始终等于相同的数字。
考虑包含范围 [1, 9] 内的整数的 3 X 3 矩阵s 。我们可以将 [1, 9] 范围内的任何数字a转换为任何其他数字b成本为|a – b| .
给定s ,通过更改其零个或多个数字以最小的成本将其转换为幻方。任务是找到最小成本。

注意:生成的矩阵必须包含 [1, 9] 范围内的不同整数。

例子:

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

这个想法是找到所有 3 X 3 幻方,并为每个幻方计算将mat更改为已知幻方的成本。结果是这些成本中最小的。
我们知道s总是 3 X 3。对于 3 X 3 矩阵,有 8 个可能的幻方。
有两种方法可以解决这个问题:
因此,通过检查整数 1、2、3、.....、9 的所有排列来计算所有 8 个幻方,并且对于每一个,如果从左上角开始将排列插入到正方形中,则检查它是否形成幻方角落。

下面是这种方法的 C++ 实现:

C++
#include 
using namespace std;
 
// Return if given vector denote the magic square or not.
bool is_magic_square(vector 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 diagonal 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 >& magic_squares)
{
    vector 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 a, vector b)
{
    int res = 0;
 
    for (int i = 0; i < 9; ++i)
        res += abs(a[i] - b[i]);
 
    return res;
}
 
// Wrapper function
int wrapper(vector v)
{
    int res = INT_MAX;
    vector > 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 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;
}


输出:

1