POJ 2261 - France '98
http://poj.org/problem?id=2261
概要
16個のチームの名前と,i 番目のチームが j 番目のチームに勝つ確率 p[i][j]
が与えられる.
トーナメントで優勝を決めるとき,各チームの優勝する確率を答える.
制約
- チーム名はきっと10文字以下
- 確率は百分率で 10^-2 の精度で出力する
解法
i 番目のチームと j 番目のチームは,(i >> k) == (j >> k)
ならば k 回戦目よりも前に既に勝負している.
k 回戦目で戦うのは,k ビット目が異なり,k ビット目より上のビットはすべて一致するような組み合わせ.
つまり,((i >> k) ^ (j >> k)) == 1
となるような i, j の組み合わせが k 回戦目で戦う.
あとはこれに従って,i 番目のチームが k 回戦目まで勝ち残っている確率を dp[i][k]
として,k = 1 ... 5 と計算していけばいい.
poj/2261.cc1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 int main() 6 { 7 char cs[16][20]; 8 for (int i = 0; i < 16; i++) { 9 scanf("%s", cs[i]); 10 } 11 int prob[16][16]; 12 for (int i = 0; i < 16; i++) { 13 for (int j = 0; j < 16; j++) { 14 scanf("%d", &prob[i][j]); 15 } 16 } 17 18 double dp[16][5]; 19 for (int i = 0; i < 16; i++) { 20 fill_n(dp[i], 5, 0.0); 21 dp[i][0] = 1.0; 22 } 23 for (int k = 1; k < 5; k++) { 24 for (int i = 0; i < 16; i++) { 25 for (int j = 0; j < 16; j++) { 26 int x = i >> (k-1); 27 int y = j >> (k-1); 28 if ((x ^ y) == 1) { 29 dp[i][k] += dp[i][k-1] * dp[j][k-1] * (prob[i][j] / 100.0); 30 } 31 } 32 } 33 } 34 for (int i = 0; i < 16; i++) { 35 printf("%-10s p=%.2f%%\n", cs[i], dp[i][4] * 100.0); 36 } 37 return 0; 38 }