poj3071_概率dp
题目链接:http://poj.org/problem?id=3071
题意:
有2^n次方个队,已知任意两个队之间每个队获胜的概率,比赛的规则相邻的两个队伍之间比赛,赢的继续下一轮,输的直接淘汰(相邻的两个队伍是指, 1,2 3,4 5,6.......也就是说2和3 不比赛。如果1,2中假设1赢了,1再跟3,4中的赢家比赛,这样最后赢的那个队一共打了n场比赛。
我们用dp[ i ][ j ]表示j参加的第i场比赛赢的概率,那么有 递推方程 dp [ i ] [ j ] = dp [ i -1 ] [ j ] *dp [ i -1 ] [ k ] *p [ j ] [ k ],j参加的第i场比赛赢,那么 j参加的第i-1场比赛肯定赢,所以有dp[i-][j] , 第i场比赛j的对手是k,j赢,所以有 p[ j ] [ k ], 那么既然k也能够打到第i场比赛,那说明k打的第i-1场比赛也一定赢,所以有 dp[ i-1 ] [ k ].
问题是k如果表示,自己想想咯
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <vector> 7 #include <cmath> 8 #include <queue> 9 #include <set> 10 #include <map> 11 #define INF 0x3f3f3f3f 12 using namespace std; 13 typedef long long LL; 14 15 double dp[8][1 << 7], p[1<<7][1<<7]; 16 int main() 17 { 18 int n; 19 while(~scanf("%d", &n)) 20 { 21 if(n == -1) 22 break; 23 for(int i = 0; i < (1 << n); i++) 24 for(int j = 0; j < (1 << n); j++) 25 scanf("%lf", &p[i][j]); 26 memset(dp, 0, sizeof(dp)); 27 for(int j = 0; j < (1<<n); j++) 28 dp[0][j] = 1; 29 for(int i = 1; i <= n; i++) 30 { 31 for(int j = 0; j < (1 << n); j++) 32 { 33 int te = j / (1 << (i-1)); 34 te ^= 1; 35 for(int k = te * (1 << (i-1)); k < te * (1 << (i-1)) + (1 << (i-1)); k++) 36 dp[i][j] += dp[i - 1][j] * dp[i - 1][k] * p[j][k]; 37 } 38 } 39 int res = 0; 40 double mm = 0; 41 for(int i = 0; i < (1 << n); i++) 42 { 43 if(mm < dp[n][i]){ 44 mm = dp[n][i]; 45 res = i + 1; 46 } 47 } 48 printf("%d\n", res); 49 } 50 return 0; 51 }