cp-problems

しおり

解説

本 \(i\) の裏表紙が本 \(j\) の表紙とくっついているとき,本 \(i\) と本 \(j\) のしおり間距離はかならず \(B_i - A_i + A_j\) になることがわかります.

そこで,\(i \to j\) のコストが \(B_i - A_i + A_j\) になる有向グラフを考えます.

ここで,本を一列に並べる操作は先述の有向グラフのハミルトン閉路を作る操作と同じであると言えます.

そこで,DFS などを用いて経路中の辺の最大コストが最小になるような経路を全探索で求めることで,\(O(N!N)\) となり \(N\le 10\) である minicase にて AC を得ることができます.

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0, _##i = (n); i < _##i; ++i)
#define INF 100000
#define MAX_N 20
int N, counter, res = INF, A[MAX_N], B[MAX_N], P[MAX_N];

signed main() {
    cin >> N;
    rep(i, N) cin >> A[i] >> B[i], B[i] -= A[i];
    rep(i, N) P[i] = i;
    do {
        counter = 0;
        rep(i, N - 1) counter = max(counter, B[P[i]] + A[P[i + 1]]);
        res = min(res, counter);
    } while (next_permutation(P, P + N));
    cout << res << endl;
}

満点解法を考えます.

TSP (巡回セールスマン問題)等で用いられる bitDP と呼ばれる,探索済みの頂点と最後に探索した頂点を用いた動的計画法を用いて,経路中の辺の最大コストの最小値を更新することで \(O(2^NN^2)\) で計算することができ,すべての testcase に対して AC を得ることができます.

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0, _##i = (n); i < _##i; ++i)
#define INF 100000
#define MAX_N 20
int N, new_max, new_bit, A[MAX_N], B[MAX_N], DP[1 << MAX_N][MAX_N];

signed main() {
    cin >> N;
    rep(i, N) cin >> A[i] >> B[i], B[i] -= A[i];
    rep(bit, (1 << N)) rep(i, N) DP[bit][i] = INF;
    rep(bit, (1 << N)) rep(i, N) if (bit & (1 << i)) rep(j, N) if (!(bit & (1 << j))) {
        new_max = DP[bit][i] == INF ? B[i] + A[j] : max(DP[bit][i], B[i] + A[j]);
        new_bit = bit | (1 << j);
        DP[new_bit][j] = min(DP[new_bit][j], new_max);
    }
    cout << *min_element(DP[(1 << N) - 1], DP[(1 << N) - 1] + N) << endl;
}

※ C / C++ などでは,ハミルトン閉路が存在するかどうかを bitDP で判定して最小値を二分探索する解法でも AC できると思います.