题目
如果一个矩阵能够满足所有的行和列都是回文序列,则称这个矩阵为一个完美矩阵。
一个整数序列 $a_1,a_2,…,a_k$,如果满足对于任何整数 $i(1≤i≤k)$,等式 $a_i=a_{k−i+1}$ 均成立,则这个序列是一个回文序列。
给定一个 $n×m$ 的矩阵$ a$,每次操作可以将矩阵中的某个元素加一或减一,请问最少经过多少次操作后,可以将矩阵 $a$ 变为一个完美矩阵?
输入格式
第一行包含整数 $T$,表示共有$ T $组测试数据。
每组数据第一行包含整数 $n$ 和 $m$,表示矩阵的大小。
接下来 $n$ 行,每行包含 $m $个整数 $a_{ij}$,表示矩阵中的元素。
输出格式
每组数据输出一行,一个答案,表示最少操作次数。
数据范围
$1≤T≤10,$
$1≤n,m≤100,$
$0≤a_{ij}≤10^9$
输入样例:
2
4 2
4 2
2 4
4 2
2 4
3 4
1 2 3 4
5 6 7 8
9 10 11 18
输出样例:
8
42
样例解释
第一组数据可以通过 8 步操作得到以下矩阵:
2 2
4 4
4 4
2 2
第二组数据可以通过 42 步操作得到以下矩阵:
5 6 6 5
6 6 6 6
5 6 6 5
思路
本题有2个难点。
第一个是如何处理所有行列都是回文序列。这里需要观察出一个性质:如果一个矩阵是完美矩阵(记为$w$),那么对于某个位置$(i,j)$,必然有$w_{i,j} = w_{n - i, j} = w_{i, m - j} = w_{n - i, m - j}$,其中$n, m$为矩阵的长宽。由这个性质我们可以将原矩阵分割成4部分(左上,右上,左下,右下),每确定一个位置,另外3个位置唯一确定,并且不同位置所对应的4元组之间相互独立。
第二个是如何在一个4元组中找到一个值,使得4个数相等的操作数最小。这里用到了绝对值不等式。$|a - x| + |b - x| + |c - x| +|d - x|$的最小值在$x$取$a, b, c, d$的中位数时取到。
代码实现
#include<iostream>
#include<set>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 110;
int w[N][N];
LL cal (set<PII> S)
{
vector<int> a;
for(auto c : S) a.push_back(w[c.first][c.second]);
sort(a.begin(), a.end());
int n = a.size();
LL res = 0;
for(int i = 0; i < n; i++)
res += abs(a[i] - a[n / 2]);
return res;
}
int main()
{
int T, n, m;
cin >> T;
while (T--) {
cin >> n >> m;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
scanf("%d", &w[i][j]);
LL res = 0;
for(int i = 0; i <= n - 1 - i; i++)
for(int j = 0; j <= m - 1 - j; j++)
res += cal({ {i, j}, {n - 1 - i, j}, {i, m - 1 - j}, {n - 1 - i, m - 1 - j}});
cout << res << endl;
}
return 0;
}
- Post link: https://scnujackychen.github.io/2021/06/22/perfect-matrix/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub IssuesGitHub Discussions