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;
}