Educational Codeforces Round #52 D. Three Pieces

http://codeforces.com/contest/1065/problem/D

我个傻 x 以为对角线移动就是 \((x,y) \rightarrow (x+d,y+d)\)。。。

问题

\(N\)\(N\) 列的国际象棋的棋盘上有一些数字,你要从 \(1\) 的位置开始,先移动到 \(2\) 的位置,然后移动到 \(3\) ,……,最后移动到 \(N^{2}\)。你只能使用主教、车、骑士三种,每一步你可以进行两种操作之一:

  • 用当前的棋子走一步。
  • 停留在当前位置,换一个棋子。

求最小的移动步数。若有多个移动步数最小的方案,输出换棋子操作数量最少的那个。

题解

大力建图跑最短路即可。

#include <bits/stdc++.h>

#ifdef LOCAL
    #define debug(...) fprintf(stderr, __VA_ARGS__)
#else
    #define debug(...) 0
#endif

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int, int> pii;

int rint() {
    int n, c, sgn = 0;
    while ((c = getchar()) < '-');
    if (c == '-') n = 0, sgn = 1;
    else n = c - '0';
    while ((c = getchar()) >= '0') {
        n = 10 * n + c - '0';
    }
    return sgn ? -n : n;
}

const int N = 123;
const int INF = 1e9;

const bool DEBUG = false;

int n;
pii p[N];
vector<pii> mv[3];
pii dist[3][15][15];
pii cost[N][3][3];
pii dp[N][3];

pair<int, int> operator + (const pii &A, const pii &B) {
    return {A.first + B.first, A.second + B.second};
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            int num;
            scanf("%d", &num);
            p[num] = {i, j};
            assert(1 <= num && num <= n * n);
        }
    }

    for (int x : {-1, 1}) {
        for (int y : {-2, 2}) {
            mv[0].emplace_back(x, y);
            mv[0].emplace_back(y, x);
        }
    }

    for (int i = 1; i < n; i++) {
        if (i == 0) continue;
        mv[1].emplace_back(i, i);
        mv[1].emplace_back(-i, -i);
        mv[1].emplace_back(i, -i);
        mv[1].emplace_back(-i, i);
    }

    for (int i = -n + 1; i < n; i++) {
        if (i == 0) continue;
        mv[2].emplace_back(i, 0);
        mv[2].emplace_back(0, i);
    }

    for (int st = 1; st < n * n; st++) {
        for (int ts = 0; ts < 3; ts++) {
            set< pair< pii, pair<int, pii> > > que;
            int xs, ys;
            tie(xs, ys) = p[st];
            for (int i = 0; i < 3; i++) {
                for (int x = 0; x < n; x++) {
                    for (int y = 0; y < n; y++) {
                        dist[i][x][y] = {INF, INF};
                    }
                }
            }
            que.insert(make_pair(make_pair(0, 0), make_pair(ts, make_pair(xs, ys))));
            dist[ts][xs][ys] = pii(0, 0);

            while (!que.empty()) {
                auto p = *(que.begin());
                que.erase(que.begin());
                int x, y;
                tie(x, y) = p.second.second;
                int t = p.second.first;
                auto d = p.first;

                for (int t2 = 0; t2 < 3; t2++) if (t != t2) {
                    if (d + pii(1, 1) >= dist[t2][x][y]) continue;
                    que.erase(make_pair(dist[t2][x][y], make_pair(t2, make_pair(x, y))));
                    dist[t2][x][y] = d + pii(1, 1);
                    que.insert(make_pair(dist[t2][x][y], make_pair(t2, make_pair(x, y))));
                }

                for (auto &p : mv[t]) {
                    int x2 = x + p.first;
                    int y2 = y + p.second;
                    assert((x != x2) + (y != y2) >= 1);
                    if (x2 < 0 || x2 >= n || y2 < 0 || y2 >= n) continue;
                    if (d + pii(1, 0) >= dist[t][x2][y2]) continue;
                    que.erase(make_pair(dist[t][x2][y2], make_pair(t, make_pair(x2, y2))));
                    dist[t][x2][y2] = d + pii(1, 0);
                    que.insert(make_pair(dist[t][x2][y2], make_pair(t, make_pair(x2, y2))));
                } 
            }

            for (int tf = 0; tf < 3; tf++) {
                int xf, yf;
                tie(xf, yf) = p[st + 1];
                cost[st][ts][tf] = dist[tf][xf][yf];
            }
        }   
    }

    for (int i = 0; i < 3; i++) {
        dp[1][i] = pii(0, 0);
    }
    for (int i = 1; i < n * n; i++) {
        for (int b = 0; b < 3; b++) {
            dp[i + 1][b] = {INF, INF};
        }
        for (int a = 0; a < 3; a++) {
            for (int b = 0; b < 3; b++) {
                dp[i + 1][b] = min(dp[i + 1][b], dp[i][a] + cost[i][a][b]);
            }
        }
    }
    auto ans = *min_element(dp[n * n], dp[n * n] + 3);
    printf("%d %d\n", ans.first, ans.second);

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hfccccccccccccc/p/9777426.html