POJ3071 Football(概率DP)

POJ3071 Football

题干:

2 n 2^n 2n个队伍打 n n n轮淘汰赛,每轮都是相邻两个队伍打,决出胜者参与下一轮。 p [ i ] [ j ] p[i][j] p[i][j]表示队伍 i i i打赢队伍 j j j的概率。问比赛打完后,获胜概率最大的队伍是哪个。

解:

d p [ i ] [ j ] dp[i][j] dp[i][j]表示比赛 j j j轮,第 i i i号队伍获胜的概率。则:

d p [ i ] [ j ] = d p [ i ] [ j − 1 ] ∗ ( ∑ k ∈ o p p o s i t e p [ i ] [ k ] ∗ d p [ k ] [ j − 1 ] ) dp[i][j]=dp[i][j-1]* (\sum_{k\in opposite}p[i][k]* dp[k][j-1]) dp[i][j]=dp[i][j1](koppositep[i][k]dp[k][j1])

d p [ i ] [ 0 ] = 1 dp[i][0]=1 dp[i][0]=1

问题是,在第 j j j轮, i i i的对手 k k k都有谁?

不妨来举例写一下(涉及二进制位运算,下标从0开始为好):

设要打 3 3 3轮淘汰赛,则会有 2 3 = 8 2^3=8 23=8支队伍,给队伍从 0 0 0开始标号,

1 1 1轮是 ( 0 , 1 ) , ( 2 , 3 ) , ( 4 , 5 ) , ( 6 , 7 ) (0,1),(2,3),(4,5),(6,7) (0,1),(2,3),(4,5),(6,7)

2 2 2轮是 ( 0 , 1 , 2 , 3 ) , ( 4 , 5 , 6 , 7 ) (0,1,2,3),(4,5,6,7) (0,1,2,3),(4,5,6,7),其中 ( 0 , 1 ) , ( 2 , 3 ) , ( 4 , 5 ) , ( 6 , 7 ) (0,1),(2,3),(4,5),(6,7) (0,1),(2,3),(4,5),(6,7)括号内的互相不能打比赛;

3 3 3轮是 ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ) (0,1,2,3,4,5,6,7) (0,1,2,3,4,5,6,7),其中 ( 0 , 1 , 2 , 3 ) , ( 4 , 5 , 6 , 7 ) (0,1,2,3),(4,5,6,7) (0,1,2,3),(4,5,6,7)括号内的互相不能打比赛。

1 1 1轮比赛涉及的队伍范围内是 2 1 = 2 2^1=2 21=2,第 2 2 2轮涉及的队伍范围是 2 2 = 4 2^2=4 22=4,第 3 3 3轮涉及的队伍范围是 2 3 = 8 2^3=8 23=8。队伍编号除以队伍范围可得:

1 1 1轮是 ( 0 , 1 ) , ( 2 , 3 ) , ( 4 , 5 ) , ( 6 , 7 ) (0,1),(2,3),(4,5),(6,7) (0,1),(2,3),(4,5),(6,7)

2 1 = 2 2^1=2 21=2 【0】 【1】【2】 【3】

2 2 2轮是 ( 0 , 1 , 2 , 3 ) , ( 4 , 5 , 6 , 7 ) (0,1,2,3),(4,5,6,7) (0,1,2,3),(4,5,6,7),其中 ( 0 , 1 ) , ( 2 , 3 ) , ( 4 , 5 ) , ( 6 , 7 ) (0,1),(2,3),(4,5),(6,7) (0,1),(2,3),(4,5),(6,7)括号内的互相不能打比赛;

2 2 = 4 2^2=4 22=4 【0】 【1】

3 3 3轮是 ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ) (0,1,2,3,4,5,6,7) (0,1,2,3,4,5,6,7),其中 ( 0 , 1 , 2 , 3 ) , ( 4 , 5 , 6 , 7 ) (0,1,2,3),(4,5,6,7) (0,1,2,3),(4,5,6,7)括号内的互相不能打比赛。

2 3 = 8 2^3=8 23=8 【0】

发现第 j j j轮比赛的队伍编号除以 2 j 2^j 2j,得到的数相同说明该轮可进行比赛;队伍编号除以 2 j − 1 2^{j-1} 2j1,得到的数相同说明上轮作为对手已经比赛过了。

所以得到第 j j j轮比赛 k k k是否作为 i i i对手的判断条件(枚举队伍编号 k k k判断是否是对手即可):

if(((k>>j)==(i>>j)) && ((k>>(j-1))!=(i>>(j-1))))
for(int j = 1; j<= n; j++)
	for(int i = 0; i < m; i ++)
		for(int k = 0; k < m; k ++)
            if(((k>>j)==(i>>j))&&((k>>(j-1))!=(i>>(j-1)))){
                 dp[i][j] += (double)dp[i][j-1]*p[i][k]*dp[k][j-1];
            }

化简版的是直接列出 k k k的所有取值。首先,对于第 j j j轮,比赛队伍集合的长度是 2 j − 2 j − 1 2^{j}-2^{j-1} 2j2j1,然后看一个集合的编号起始值是多少。

可知对于第 j j j轮的第 i i i号队伍,所在的比赛队伍集合的起始编号是 [ i 2 j ] ∗ 2 j [\frac{i}{2^{j}}]*2^j [2ji]2j,但是还要排除掉不能打的队伍。考虑上一轮的情况,如果编号 i i i除以 2 j − 1 2^{j-1} 2j1是偶数,说明在第 j j j轮小集合合并后,会跟新集合后半部分的队伍打,所以起始编号应该是原来的值 + 2 j − 1 +2^{j-1} +2j1;如果是奇数,说明在第 j j j轮小集合合并后,会跟新集合前半部分的队伍打,起始编号即为 [ i 2 j ] ∗ 2 j [\frac{i}{2^{j}}]*2^j [2ji]2j

所以:

st = ((i>>j)<<j) + (((i>>(j-1)) & 1)?0:(1<<(j-1)));
len = (1<<j)-(1<<(j-1));
ed = st - 1 + len;
for(int j = 1; j<= n; j++)
   for(int i = 0; i < m; i ++){
       int st = ((i>>j)<<j) + (((i>>(j-1)) & 1)?0:(1<<(j-1))), len = (1<<j)-(1<<(j-1));
       for(int k = st; k <= st-1+len; k++)
           dp[i][j] += (double)dp[i][j-1]*p[i][k]*dp[k][j-1];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值