この問題に似てた
問題概要
の順列 を最適化したい。以下の手順にしたがって、各要素 のスコアが定まる。この 個のスコアの最大値の最小値を求めよ。
- 値が のいずれかであるような数列 ( 項) が与えられる
- に対して、順列中の 、 であるような に対して
- ならば、要素 のスコアを 1 加算する
- ならば、要素 のスコアを 1 加算する
- 最後に であるような に対して のスコアを 1 加算する
制約
考えたこと
まず が大きいのは完全にどうでもよい。なぜなら操作の順序はどうでもいいので、
- num[ i ][ j ] := 要素 i と要素 j に関するクエリの個数
という風にしてしまえば、 回の処理を考えればよくなるからだ。
さて、順列を最適化する問題なので、第一感では bitDP を考えたくなる。そして実際に bitDP で解くことができる。
- dp[ bit ] := のうち、bit で表される要素のみを先に並べてしまったときに、その内部におけるスコアの最大値の最小値
とすれば OK。これを効率よく更新するために、前処理として以下の値を求めておく。
- score[ bit ][ v ] := bit で表される要素がすでに並んでいる状態で、その直後に要素 v を並べたときの要素 v のスコア
注意したいことは、この値が (bit, v) の組のみに依存するということだ。むしろその構造を見抜くことがこの問題のポイントだと言えそう。この score を前処理しておけば、
chmin(dp[ bit | (1 << v) ], max(dp[ bit ], score[ bit ][ v ])
という遷移によって DP できる。
#include <bits/stdc++.h> using namespace std; template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; } template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; } const int INF = 1<<29; int main() { int N, M; cin >> N >> M; vector<int> a(N); for (int i = 0; i < N; ++i) cin >> a[i], --a[i]; vector<vector<int>> num(M, vector<int>(M, 0)); for (int i = 0; i + 1 < N; ++i) num[a[i]][a[i+1]]++; // 前処理 vector<vector<int>> score(1<<M, vector<int>(M, INF)); for (int bit = 0; bit < (1<<M); ++bit) { int base = 0; for (int j = 0; j < M; ++j) { if (!(bit & (1<<j))) continue; for (int k = 0; k < M; ++k) { if (bit & (1<<k)) continue; base += num[j][k] + num[k][j]; } } for (int v = 0; v < M; ++v) { if (bit & (1<<v)) continue; int add = 0, sub = 0; for (int j = 0; j < M; ++j) { if (!(bit & (1<<j))) continue; sub += num[j][v]; // [j, v) は除外 } for (int k = 0; k < M; ++k) { if ((bit & (1<<k))) continue; if (k == v) continue; add += num[v][k]; // [v, k) は追加 } score[bit][v] = base + add - sub + (v == a.back()); } } // bitDP vector<int> dp(1<<M, INF); dp[0] = 0; for (int bit = 0; bit < (1<<M); ++bit) { for (int v = 0; v < M; ++v) { if (bit & (1<<v)) continue; int nbit = bit | (1<<v); chmin(dp[nbit], max(dp[bit], score[bit][v])); } } cout << dp[(1<<M) - 1] << endl; }