AT_abc332_d题解

AT_abc332_d题解

题意简述:给你大小为 $h \times w$ 的两个二维数组 $a$ 和 $b$。每次能交换 $a$ 中相邻的两行或两列,问最少交换几次能使 $a$ 与 $b$ 完全相等,如果不能使 $a$ 和 $b$ 完全相等,输出 $-1$,否则输出最小的交换次数。

注意到 $2 \le h,w \le 5$ ,所以我们选择 乱搞 爆搜。

如果你没有头脑的交换任意两行、两列,你应该会超时。所以...

我们可以用 next_permutation 求出每一行、每一列的全排列,然后暴力检查并统计最小的交换次数,那么时间复杂度为 $O(h! w! h w)$。

具体实现:我们再开两个一维数组 $r$ 和 $c$ 存 $a$ 数组经过交换后的位置(初始值为 $1$ ~ $n$),然后先判断看是否与 $b$ 相等,相等的话就统计最小的操作数。

这样说比较抽象,形象一点理解就是:$r_i$ 表示之前的第 $i$ 行,现在到了第 $r_i$ 行($c$ 同理)。

如果你还不懂,还可以这样理解:$a_{i,j}$ 等于交换后的 $a_{r_i, c_j}$。

所以这道题就解完了。

代码:

#include <algorithm>
#include <iostream>

using namespace std;

const int N = 10;

int n, m, a[N][N], b[N][N], ans = 2147483647;
int r[N], c[N];

bool check()
{
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= m; j ++ )
        {
            if (a[r[i]][c[j]] != b[i][j]) return false;
        }
    }
    return true;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= m; j ++ ) scanf("%d", &a[i][j]);
    }
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= m; j ++ ) scanf("%d", &b[i][j]);
    }

    for (int i = 1; i <= n; i ++ ) r[i] = i;
    for (int i = 1; i <= m; i ++ ) c[i] = i;

    do
    {
        int t1 = 0;
        for (int i = 1; i <= n; i ++ )
        {
            for (int j = i + 1; j <= n; j ++ ) if (r[i] > r[j]) t1 ++ ;
        }
        do
        {
            if (!check()) continue;
            int t2 = 0;
            for (int i = 1; i <= m; i ++ )
            {
                for (int j = i + 1; j <= m; j ++ ) if (c[i] > c[j]) t2 ++ ;
            }
            ans = min(ans, t1 + t2);
        }
        while (next_permutation(c + 1, c + 1 + m));
    }
    while (next_permutation(r + 1, r + 1 + n));

    if (ans == 2147483647) printf("-1\n");
    else printf("%d\n", ans);
    return 0;
}
posted @ 2023-12-11 08:01  emo_male_god  阅读(27)  评论(0)    收藏  举报  来源