表が\(A_i\)、裏が\(B_i\)、と書かれた\(N\)枚のカードがある。「隣り合う2枚を選択して、入れ替えて裏返す」という操作をして、カードの並びが広義単調増加になる最小回数を求めよ。N)$$考え方その1(DP)制約が特殊なので、どのような計算量になるかの想像はしやすいでしょう。\(N\)が20前後の時は\(O(2^N)\)が関係してくることが多いです。全探索することを考えてみます。カードの並べ方は\(N!\)通りあるので、実際にこの通り並べてみて、広義単調増加になっている物の中でswap回数が最小のものを見つければ良いです。奇数→\(B_i\)となっています。全てのカードについて\(A_i\)か\(B_i\)なのかを考えれば、カードが広義単調増加になっているのかを\(O(N)\)もあれば判定できます。\(N!\)通りの全探索は今回の制約では間に合わないので何らかの工夫が求められます。今回のように隣接swap系の問題は似たようなDPで解けることが多いようです。dp[S][last]:=集合Sで表されるカードを、左に詰めてソートした時の最小のswap回数(転倒数)。最後に加えたものの値をlastとする。するとうまくできます。更新式を考える前に、動的計画法を使わずにdp[S][last]をどのように求めたらよいか考えてみます。Sが分かっていれば、swap回数は以下のように計算できます。Sから選択していないものの中で、最小の要素のうち、一番前にあるものを選ぶ先頭に来るようにswapする1に戻るつまり、選択ソートのようにしてやれば、Sから最小のswap回数を求めることができます。更新式は、このソートをイメージするとわかりやすいです。ソートされた部分の一番最後は、一番最後に選択される必要があります。解法dp[S][last]:=集合Sで表されるカードを、左に詰めてソートした時の最小のswap回数(転倒数)。最後に加えたものの値をlastとする。最後に置かれる時のみを考えれば良いです。更新式は以下の通りです。i_valは以下のような値です。0;}考え方その2(表か裏かを最初に決める)別の考え方もあります。先に各カードごとに、表(\(A_i\))になるのか裏(\(B_i\))になるのかを決めてしまうと、これは\(O(2^N)\)通りあります。奇数カードの並びが広義単調増加を満たすように並べられるかを判定し、転倒数を求めればOKです。これの判定が難しく、適当にやるとWAになってしまいます。バブルソートをしてから偶奇性を満たすかどうか判定すると、同じ数がいくつかある時にWAになる可能性があります。数番目になるのか奇数番目になるのかが決定されます。以下のような同じ数がいくつか登場する場合では、正しい並べ方が存在する時でも、それとバブルソートでの並べ方が異なる可能性があります。同じ数が複数ある時は、広義単調増加であるような並べ方が複数存在することになるので、先に全体の並び方を決定して偶奇性を確認するためには、全ての並べ方を確認する必要があります。(先程の例では1つしか確認していない)。逆に、偶奇性を必ず満たすように、偶数の物と奇数の物に分けてソートしてやれば、正しい並べ方が存在するならそれと同じになり、存在しない場合は全体として広義単調増加になりません。これなら1通りの確認で済みます。全体で考えても広義単調増加となっていることに注目すると良いです。解法まず各カードごとに、表(\(A_i\))になるのか裏(\(B_i\))になるのかを決めます。2]\)枚であるので、これを満たすものだけについて考えましょう。最終的に偶数番目に到達するものでソート最終的に奇数番目に到達するものでソート全体で広義単調増加になっているかを判定し転倒数を計算とすれば良いです。コメントをキャンセルメールアドレスが公開されることはありません。*次回のコメントで使用するためブラウザーに自分の名前、メールアドレス、サイトを保存する。上に表示された文字を入力してください。