POJ3071 Football
题目传送门
思路
状态设计
考虑到让求在第 \(n\) 轮比赛(决赛)中获胜概率最大的球队。因此,我们需要知道每一轮中,每个队伍的获胜概率。\(\\\)
因此设 \(dp_{i, j}\) 为在第 \(i\) 轮时,\(j\) 获胜的概率。\(\\\)
转移方程
由于我们要知道球队 \(j\) 在第 \(i\) 轮比赛中的胜率,所以就要算出它与所有【在上一轮比赛中可能获胜的球队 \(k\)】对战的胜率之和,即就是:
\[dp_{i, j} = \sum_{k \in \left\{x|可能与 j 对战的球队 \right\}} dp_{i - 1, j} \times dp_{i - 1, k} \times p_{j, k}
\]
当然还要考虑有哪些 \(k\) 可能与 \(j\) 对战:\(\\\)
- 对于第 \(i\) 轮比赛,它一共包含(所有比赛还未开始时的)\(2^i\) 支球队,因此我们可以将这 \(2^n\) 个球队以每 \(2^i\) 个为一组分成若干块。\(\\\)
对于要对战的球队 \(j, k\),我们首先要看他们是否在同一个块中,即看:
\(\frac{j + 2^i - 1}{2^i} = \frac{k + 2^i - 1}{2^i}\)是否成立。 - 假如我们现在判断出了 \(j, k\) 已经在这样一个 \(2^i\) 的大块中了,那么我们将这个大块均分成两个大小为 \(2^{i - 1}\) 的小块(即模拟上一轮比赛中可能包含的队伍),我们就要更近一步判断 \(j, k\) 是否分属于两个不同的小块,这样才合法(因为若在同一个小块中,由于前提是 \(j\) 已经进入了第 \(i\) 轮,所以这个小块中的其他球队不可能再与之对战)。因此,要看 \(\frac{j + 2^{i - 1} - 1}{2^{i - 1}} \neq \frac{k + 2^{i - 1} - 1}{2^{i - 1}}\) 是否成立。
边界条件
在进行第 \(0\) 轮比赛(即还没有开始比赛)时,每个球队一定晋级,即:\(dp_{0, j} = 1, j \in [1, n]\)。
答案
就是 \(max \left\{dp_{n, i} \right\}\) 的 \(i\)。
复杂度
空间 \(O(n \times 2^n)\),时间 \(O(n^2 \times 2^n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = (1 << 7) + 7;
int n, m;
double p[maxn][maxn];
double dp[15][maxn];
int main() {
scanf("%d", &m), n = 1 << m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
scanf("%lf", &p[i][j]);
int x; scanf("%d", &x);
for (int i = 1; i <= n; ++i) dp[0][i] = 1;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
for (int k = 1; k <= n; ++k) {
if (j == k) continue;
if ((j + (1 << i) - 1) / (1 << i) != (k + (1 << i) - 1) / (1 << i)) continue;
if (abs((j + (1 << i - 1) - 1) / (1 << i - 1) -
(k + (1 << i - 1) - 1) / (1 << i - 1)) != 1) continue;
dp[i][j] += dp[i - 1][j] * dp[i - 1][k] * p[j][k];
}
}
}
double maxp = 0;
int id = 0;
for (int i = 1; i <= n; ++i)
if (maxp < dp[m][i])
maxp = dp[m][i], id = i;
printf("%d\n", id);
return 0;
}

浙公网安备 33010602011771号