完美矩阵(回文)

题目描述
如果一个矩阵能够满足所有的行和列都是回文序列,则称这个矩阵为一个完美矩阵。

一个整数序列 a1,a2,…,ak,如果满足对于任何整数 i(1≤i≤k),等式 ai=ak−i+1 均成立,则这个序列是一个回文序列。

给定一个 n×m 的矩阵 a,每次操作可以将矩阵中的某个元素加一或减一,请问最少经过多少次操作后,可以将矩阵 a 变为一个完美矩阵?

输入格式
第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含整数 n 和 m,表示矩阵的大小。

接下来 n 行,每行包含 m 个整数 aij,表示矩阵中的元素。

输出格式
每组数据输出一行,一个答案,表示最少操作次数。

数据范围
1≤T≤10,
1≤n,m≤100,
0≤aij≤109

样例
输入样例:
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

(暴力枚举)
保证回文的话,就需要让四个角落的值相等
求次数最少,那就看这四个数怎么排
第一时间想到的是中间的数(中位数),这样肯定操作的次数最少的
那么是不是其他的数呢?比如平均数
这四个数设为a,b,c,d

设平均数是avg
平均数的答案是(下面的不等式是三角绝对值不等式)
|a−avg|+|b−avg|+|c−avg|+|d−avg||a−avg|+|b−avg|+|c−avg|+|d−avg|
>=|a+b−2∗avg|+|d+c−2∗avg|>=|a+b−2∗avg|+|d+c−2∗avg|
=|2∗avg−(a+b)|+|d+c−2∗avg|=|2∗avg−(a+b)|+|d+c−2∗avg|
>=|d+c−a−b|>=|d+c−a−b|
=d+c−a−b=d+c−a−b
中位数的答案是
|a−b|+|b−b|+|c−b|+|d−b||a−b|+|b−b|+|c−b|+|d−b|
=b−a+c−b+d−b=b−a+c−b+d−b
=d+c−b−a=d+c−b−a
所以中位数的答案小于平均数
中位数更优

时间复杂度 O(n^2)
参考文献
C++ 代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1010;
int t,n,m;
int a[N][N],s[10];
int main()
{
    cin>>t;
    while(t--)
    {
        LL res=0;
        cin>>n>>m;
        for (int i = 1; i <= n; i ++ )
           for (int j = 1; j <= m; j ++ )
               cin>>a[i][j];

        for (int i = 1; i <= n; i ++ )
           for (int j = 1; j <= m; j ++ )
           {
               s[1]=a[i][j];
               s[2]=a[i][m-j+1];
               s[3]=a[n-i+1][j];
               s[4]=a[n-i+1][m-j+1];
               sort(s+1,s+1+4);
               for(int k = 1; k <= 4; k ++ )
                res+=abs(s[k]-s[2]);
           }
           cout<<res/4<<'\n';
    }
    return 0;
}

Java代码

import java.io.*;
import java.util.*;
import java.lang.*;
public class Main{
    public static void main(String[] args){
        Scanner cin = new Scanner(System.in);
        int t = cin.nextInt();
        while(t--!=0)
        {
            int n=cin.nextInt(),m=cin.nextInt();
            int [][] a = new int[n+1][m+1];
            int []s= new int [10];
            for(int i = 0; i < n; i++)
                for(int j = 0; j < m; j++)
                    a[i][j] = cin.nextInt();
            long res=0;
            for(int i=0;i<n;i++)
              for(int j=0;j<m;j++)
              {
                  s[1] = a[i][j];
                  s[2] = a[n - i - 1][j];
                  s[3] = a[i][m - j - 1];
                  s[4] = a[n - i - 1][m - j - 1];
                  Arrays.sort(s,1,4);
                  for(int k = 1; k <= 4; k ++ )
                  res+=Math.abs(s[k]-s[2]);
              }
            System.out.println(res/4);
        }
        return ;
    }
}

GO代码

package main
import (
    "fmt" 
    "sort"
)
const N = 110

var a[N][N]int

func abs(x int)int{
    if x < 0{
        x = -x
    }
    return x
}
func main(){
    var T int
    fmt.Scanf("%d",&T)
    for ;T > 0;{
        T --
        var n,m int
        fmt.Scanf("%d %d",&n,&m)
        for i := 1;i<= n;i ++{
            for j := 1;j <= m;j ++{
                fmt.Scanf("%d",&a[i][j])
            }
        }
        u,v := n,m
        res := 0
        for i := 1;i <= u;i ++{
            for j := 1;j<=v;j ++{
                point := []int{a[i][j],a[i][m - j + 1],a[n - i + 1][j],a[n- i + 1][m - j + 1]}
                sort.Slice(point,func(i,j int)bool{
                    if point[i] < point[j]{
                        return true
                    }
                    return false
                })
                res += point[3] - point[0] + point[2] - point[1]
            }
        }
        fmt.Println(res/4)
    }
}

欢迎留言点赞

嗷嗷嗷~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值