[POJ 3071]Football[概率DP]
[POJ 3071]Football[概率DP]
题目大意
有 2n 个编号为 1,2,3,…,2n 的队伍进行足球比赛,一开始 1 和 2 打,3 和 4 打... 赢得队伍按照原来的相对顺序重新编号 1,2,…,2n−1,按上规则进行比赛。给出一个胜率的概率矩阵,求最终最可能获胜的队伍。
数据范围:多组数据,n≤7。
解题方法
用 f[i][j] 表示进行 i 场比赛,j 获胜的概率,可以得到转移方程:
f[i][j]=∑f[i−1][j]×f[i−1][t]×p[j][t]
其中 t 是在第 i 场比赛中可能与 j 交手的队伍,现在问题关键在于如何求解 t。
一开始的队伍 1,2,…,2n 可以被分为 2n−1 组,每个队可能和一个队打,容易发现第 i 场时 j 的对手可能有 2i−1 个,整个 1,2,…,2n 可以被分为 2n−i 组。所以只要知道当前 j 在第几组即可,可以知道在第
j−12i−1+1
组。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 257;
double p[N][N], dp[N][N];
int n;
int main() {
while(true) {
scanf("%d", &n);
if(n < 0) break;
for(int i = 1; i <= (1 << n); i++)
for(int j = 1; j <= (1 << n); j++) scanf("%lf", &p[i][j]);
memset(dp, 0, sizeof dp);
for(int i = 1; i <= (1 << n); i++) dp[0][i] = 1;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= (1 << n); j++) {
int cur = (j - 1) / (1 << (i - 1));
if(cur & 1) {
for(int t = (cur - 1) * (1 << (i - 1)) + 1; t <= cur * (1 << (i - 1)); t++) {
dp[i][j] += dp[i - 1][j] * dp[i - 1][t] * p[j][t];
}
} else {
for(int t = (cur + 1) * (1 << (i - 1)) + 1; t <= (cur + 2) * (1 << (i - 1)); t++) {
dp[i][j] += dp[i - 1][j] * dp[i - 1][t] * p[j][t];
}
}
}
}
double pWin = dp[n][1]; int winner = 1;
for(int i = 2; i <= (1 << n); i++) {
if(pWin < dp[n][i]) pWin = dp[n][i], winner = i;
}
printf("%d\n", winner);
}
return 0;
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步