POJ--3071(概率DP)

2014-12-29 22:14:20

思路:这道题我醉了....

  思路很巧妙,用dp[i][j]来表示第i轮j赢的概率,那么就要让第i-1轮后j仍然存活。

  有转移方程:dp[i][j] = Sima(dp[i - 1][j] * dp[i - 1][k] * P[j][k],(P[j][k]表示j打败k的概率,要注意这个k的选择,这里很巧妙地运用了位运算,算出所有能在第i轮和j对位的k,

    用(((j >> (i - 1)) ^ 1) == (k >> (i - 1)),来判断是否处于同一颗子树,且有机会使得j和k在第i轮对位,注意人的下标从0开始!,思考。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <iostream>
11 #include <algorithm>
12 using namespace std;
13 #define lp (p << 1)
14 #define rp (p << 1|1)
15 #define getmid(l,r) (l + (r - l) / 2)
16 #define MP(a,b) make_pair(a,b)
17 typedef long long ll;
18 typedef unsigned long long ull;
19 const int INF = 1 << 30;
20 
21 int N;
22 double dp[10][150],P[150][150];
23 
24 int main(){
25     while(scanf("%d",&N) != EOF){
26         if(N == -1)
27             break;
28         int sz = 1 << N;
29         for(int i = 0; i < sz; ++i)
30             for(int j = 0; j < sz; ++j)
31                 scanf("%lf",&P[i][j]);
32         memset(dp,0,sizeof(dp));
33         for(int i = 0; i < sz; ++i)
34             dp[0][i] = 1.0;
35         for(int i = 1; i <= N; ++i){
36             for(int j = 0; j < sz; ++j){
37                 for(int k = 0; k < sz; ++k){
38                     if(((j >> (i - 1)) ^ 1) == (k >> (i - 1)))
39                         dp[i][j] += dp[i - 1][j] * dp[i - 1][k] * P[j][k];
40                 }
41             }
42         }
43         int ans = 0;
44         for(int i = 1; i < sz; ++i)
45             if(dp[N][i] > dp[N][ans])
46                 ans = i;
47         printf("%d\n",ans + 1);
48     }
49     return 0;
50 }
51     

 

posted @ 2014-12-29 22:17  Naturain  阅读(102)  评论(0编辑  收藏  举报