abc332D 将矩阵A变成B的最小步数

题面:给定两个H行W列的矩阵A和B,每次操作可以交换相邻的行或列,问是否可以将A变成B?如果可以,输出最少操作步数;如果不行,输出-1。
范围:2<=H,W<=5, 1<=A[i][j],B[i][j]<=1e9

思路:数据规模小,直接bfs搜索,如果范围再大点可以用双向bfs优化效率。需要用到哈希来快速判重。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,a,b) for(int i=a; i<=b; i++)
#define per(i,a,b) for(int i=b; i>=a; i--)

using hval = tuple<int,int,int>;
const int B1 = 131, M1 = 1000000123;
const int B2 = 137, M2 = 1000000223;
const int B3 = 139, M3 = 1000000007;

const int N = 6;
using Arr = array<array<int,N>,N>;
int H, W;
Arr A, B;
hval HB;
set<hval> vis;

hval encode(Arr a) {
    int x = 0, y = 0, z = 0;
    rep(i,1,H) rep(j,1,W) {
        x = (x * B1 + a[i][j]) % M1;
        y = (y * B2 + a[i][j]) % M2;
        z = (z * B3 + a[i][j]) % M3;
    }
    return {x,y,z};
}

void bfs() {
    HB = encode(B);
    queue<tuple<Arr,hval,int>> q;
    hval HA = encode(A);
    q.push({A,HA,0}); vis.insert(HA);
    while (!q.empty()) {
        auto [t,h,d] = q.front(); q.pop();
        if (h == HB) {
            cout << d << "\n";
            return;
        }
        rep(i,1,H-1) {
            Arr x = t;
            rep(j,1,W) swap(x[i][j], x[i+1][j]);
            hval hx = encode(x);
            if (vis.count(hx) == 0) {
                q.push({x,hx,d+1}); vis.insert(hx);
            }
        }
        rep(j,1,W-1) {
            Arr x = t;
            rep(i,1,H) swap(x[i][j], x[i][j+1]);
            hval hx = encode(x);
            if (vis.count(hx) == 0) {
                q.push({x,hx,d+1}); vis.insert(hx);
            }
        }
    }
    cout << -1 << "\n";
}
void solve() {
    cin >> H >> W;
    rep(i,1,H) rep(j,1,W) cin >> A[i][j];
    rep(i,1,H) rep(j,1,W) cin >> B[i][j];
    bfs();
}

signed main() {
    cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    while (t--) solve();
    return 0;
}
posted @ 2024-03-08 12:27  chenfy27  阅读(11)  评论(0编辑  收藏  举报