まあ基本だよね。
No.753 最強王者決定戦 - yukicoder
問題
16人の人間がいる。この16人を一列に並べて順番に組を作ってトーナメントを行ったとき、並べ方に応じて優勝者がただ一人決まる。全てのペアについて、戦ったときどちらが勝つかは決まっている。16!通りの並べ方全てについて優勝者を求めたとき、各人が何回優勝するかを計算せよ。
解法
DPで解く。DPテーブルは以下のようにする。
DP[i][S]: 集合Sの中の人が全員戦った時に人iが優勝する場合の数。ただし、組み方が同じで人の並べ方だけが違うものは同一視する。
(|S|は2べきのみを取り得ることに注意。)
DPの遷移はDP[i][S] <- DP[i][T] * DP[j][S - T] (iがjに勝つ場合)である。
計算量解析はかなり複雑。とりあえずΩ(2^n n^2)とO(4^n n^2)は確定だけどその間が詰められない。
実装上の注意点
- 16!が64bit整数に収まるか注意する。今回はスターリングの公式から16! ~= (16/e)^16 < 8^16 = 2^48なので問題ない。
- 同じトーナメントを何回も数えるので、最後に然るべき数を掛けるのを忘れないようにする。(今回は2^15)
提出: #305265 No.753 最強王者決定戦 - yukicoder (Rust)
/// Generates an Iterator over subsets of univ, in the descending order. /// Verified by: http://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=3050308 struct SubsetIter { bits: Option<usize>, univ: usize } impl Iterator for SubsetIter { type Item = usize; fn next(&mut self) -> Option<usize> { match self.bits { None => None, Some(bits) => { let ans = bits; self.bits = if bits == 0 { None } else { Some((bits - 1) & self.univ) }; Some(ans) } } } } fn subsets(univ: usize) -> SubsetIter { SubsetIter { bits: Some(univ), univ } } fn solve() { let out = std::io::stdout(); let mut out = BufWriter::new(out.lock()); macro_rules! puts { ($format:expr) => (write!(out,$format).unwrap()); ($format:expr, $($args:expr),+) => (write!(out,$format,$($args),*).unwrap()) } let n = 16; input! { a: [[i32; n]; n] } let mut a = a; for i in 0 .. n { for j in i + 1 .. n { a[j][i] = -a[i][j]; } } let mut dp = vec![vec![0i64; 1 << n]; n]; for i in 0 .. n { dp[i][1usize.wrapping_shl(i as u32)] = 1; } let mut s = 1; while s < n as u32 { s *= 2; for bits in 0 .. 1usize << n { if bits.count_ones() != s { continue; } for sub in subsets(bits) { if sub.count_ones() != s / 2 { continue; } let sub2 = bits - sub; for i in 0 .. n { if (sub & 1 << i) == 0 { continue; } for j in 0 .. n { if (sub2 & 1 << j) == 0 { continue; } if a[i][j] == 1 { dp[i][bits] += dp[i][sub] * dp[j][sub2]; } } } } } } for i in 0 .. n { puts!("{}\n", dp[i][(1 << n) - 1] << (n - 1)); } }
まとめ
なんで入力長を固定にしたり対称行列にしなかったりしたんだ…?