POJ3071 - Football

\(i\) 轮比赛相当于大小为 \(2^i\) 的小比赛里的单挑,赛场中点两侧的的可以两两单挑。

\(f(r,i)\) 表示第 \(r\) 轮中队伍 \(i\) 存活的概率,\(w(i,j)\) 为输入给出的 \(i\) 战胜 \(j\) 的概率,有
\[ f(r,i) = \sum{f(r-1,i) f(r-1,j)w(i,j)} \]
答案是 \(\max{f(n,i)}\)

#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 8;

double f[N][1 << N];
double w[1 << N][1 << N];

int main() {
  int n;
  while (~scanf("%d", &n)) {
    if (n == -1) {
      break;
    }
    int nn = (1 << n);
    for (int i = 0; i < nn; i++) {
      for (int j = 0; j < nn; j++) {
        scanf("%lf", &w[i][j]);
      }
    }
    for (int r = 1; r <= n; r++) {
      for (int i = 0; i < nn; i++) {
        f[r][i] = 0.0;
      }
    }
    for (int i = 0; i < nn; i++) {
      f[0][i] = 1.0;
    }
    for (int r = 0; r < n; r++) {
      int len = (2 << r);
      for (int s = 0; s < nn - len + 1; s += len) {
        int t = s + len - 1;
        int mi = (s + t) >> 1;
        for (int i = s; i <= mi; i++) {
          for (int j = mi + 1; j <= t; j++) {
            f[r + 1][i] += f[r][i] * f[r][j] * w[i][j];
            f[r + 1][j] += f[r][i] * f[r][j] * w[j][i];
          }
        }
      }
    }
    double best = 0.0;
    int bid = -1;
    for (int i = 0; i < nn; i++) {
      if (best < f[n][i]) {
        bid = i;
        best = f[n][i];
      }
    }
    printf("%d\n", bid + 1);
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/arg-53/p/9244940.html