题目:
https://ac.nowcoder.com/acm/problem/107668
给你 2 n 2^n 2n个球队,每一轮相邻的球队进行比赛。告诉你 i i i球队战胜 j j j球队的概率为 P i j P_{ij} Pij,问最后哪支球队赢得概率最大!
思路:
令 f ( i , j ) f(i,j) f(i,j)表示球队 i i i能够晋级第 j j j轮的概率,初始为第 0 0 0轮, f ( i , 0 ) = 1 f(i,0)=1 f(i,0)=1,然后对于所有可能在第 j j j轮和球队 i i i比赛的球队 k k k,有
f ( i , j ) = ∑ k f ( i , j − 1 ) ∗ P i k ∗ f ( k , j − 1 ) f(i,j)=\sum_{k}f(i,j-1)*P_{ik}*f(k,j-1) f(i,j)=k∑f(i,j−1)∗Pik∗f(k,j−1)
解释就是 i i i球队晋级第 j j j轮就要先晋级第 j − 1 j-1 j−1轮,并且打败 j − 1 j-1 j−1轮所有可能的对手。
另外我们可以确定球队i在第j轮是第几个,比如
第 0 0 0轮 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 1,2,3,4,5,6,7,8 1,2,3,4,5,6,7,8
第 1 1 1轮 1 , 3 , 5 , 7 1,3,5,7 1,3,5,7
第 2 2 2轮 3 , 5 3,5 3,5
第 3 3 3轮 5 5 5
观察 5 5 5,会发现球队 i i i在第 j j j轮的位置为 ⌈ i 2 j ⌉ \lceil\frac{i}{2^j}\rceil ⌈2ji⌉,相当于第 j j j轮以 2 j 2^j 2j为一组,每组胜出一个人,则 i i i就是第 ⌈ i 2 j ⌉ \lceil\frac{i}{2^j}\rceil ⌈2ji⌉组。
- 如果 ⌈ i 2 j ⌉ \lceil\frac{i}{2^j}\rceil ⌈2ji⌉为奇数,则和 ⌈ i 2 j ⌉ + 1 \lceil\frac{i}{2^j}\rceil+1 ⌈2ji⌉+1组打。
- 如果 ⌈ i 2 j ⌉ \lceil\frac{i}{2^j}\rceil ⌈2ji⌉为偶数,则和 ⌈ i 2 j ⌉ − 1 \lceil\frac{i}{2^j}\rceil-1 ⌈2ji⌉−1组打。
#include<stdio.h>
#include<cstring>
using namespace std;
const int N=8;
const int eps=1e-6;
double a[1<<N][1<<N],f[1<<N][N],maxi;
int n,locate;
double dfs(int x,int y)
{
if(f[x][y])
return f[x][y];
f[x][y]=0;
int tu=x%(1<<(y-1))?x/(1<<(y-1))+1:x/(1<<(y-1));//x为第几个
tu=tu%2?tu+1:tu-1;//x和哪组打
for(int i=1; i<=1<<n; i++)//枚举可能的对手
{
int tu1=i%(1<<(y-1))?i/(1<<(y-1))+1:i/(1<<(y-1));
if(tu1==tu)
f[x][y]+=a[x][i]*dfs(i,y-1);
}
f[x][y]*=dfs(x,y-1);
return f[x][y];
}
int main()
{
while(scanf("%d",&n)==1&&n!=-1)
{
for(int i=1; i<=1<<n; i++)
for(int j=1; j<=1<<n; j++)
scanf("%lf",&a[i][j]);
for(int i=1; i<=1<<n; i++)
f[i][0]=1.0;
for(int i=1; i<=1<<n; i++)
{
double res=dfs(i,n);
if(res-maxi>eps)
maxi=res,locate=i;
}
printf("%d\n",locate);
}
return 0;
}