poj 3071 概率dp

//分析:明显的树形关系,题目描述的是一棵高 n + 1的完全二叉树,则 dp[树层号][team号](规定最底层为 0 层,层数朝节点的方向依次递增),推一下就好了

//稍微需要想一下的是比赛双方的选取,下面给出两种方法

//#1 枚举起点划分team区间

 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "algorithm"
 5 using namespace std;
 6 double dp[10][130], mat[130][130];
 7 int n;
 8 
 9 int main()
10 {
11     int i, j, k, t;
12     while(scanf("%d", &n) && (n != -1)) {
13         for(i = 1; i <= (1 << n); ++i)
14             for(j = 1; j <= (1 << n); ++j)
15                 scanf("%lf", &mat[i][j]);
16         memset(dp, 0, sizeof(dp));
17         int tot = 1 << n, half;
18         for(i = 1; i <= tot; ++i)
19             dp[0][i] = 1;
20         for(i = 1; i <= n; ++i) {
21             tot = 1 << i, half = 1 << (i - 1);
22             for(j = 1; j <= (1 << n); j += tot) {
23                 for(k = j; k <= j + half - 1; ++k) {
24                     for(t = j + half; t <= j + tot - 1; ++t) {
25                         dp[i][k] += dp[i - 1][k] * dp[i - 1][t] * mat[k][t];
26                         dp[i][t] += dp[i - 1][k] * dp[i - 1][t] * mat[t][k];
27                     }
28                 }
29             }
30         }
31         double ans = 0;
32         int res = 1;
33         for(i = 1; i <= (1 << n); ++i)
34             if(ans < dp[n][i])
35                 ans = dp[n][i], res = i;
36         printf("%d\n", res);
37     }
38 }

 

//#2 比较向上 i - 1 层的根节点序号(存在提前相遇情况)

 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "algorithm"
 5 using namespace std;
 6 double dp[10][130], mat[130][130];
 7 int n;
 8 
 9 int main()
10 {
11     int i, j, k;
12     while(scanf("%d", &n) && (n != -1)) {
13         for(i = 1; i <= (1 << n); ++i)
14             for(j = 1; j <= (1 << n); ++j)
15                 scanf("%lf", &mat[i][j]);
16         memset(dp, 0, sizeof(dp));
17         for(i = 1; i <= (1 << n); ++i)
18             dp[0][i] = 1;
19         for(i = 1; i <= n; ++i) {
20             for(j = 1; j <= (1 << n); ++j) {
21                 for(k = 1; k <= (1 << n); ++k) {
22                     int root_j = (j - 1) >> (i - 1), root_k = (k - 1) >> (i - 1);
23                     if(root_j != root_k && (root_j >> 1) == (root_k >> 1)) {    //向上 i - 1 层的根节点不同 且 是同一节点的左右孩子
24                         dp[i][j] += dp[i - 1][j] * dp[i - 1][k] * mat[j][k];
25                         dp[i][k] += dp[i - 1][j] * dp[i - 1][k] * mat[k][j];
26                     }
27                 }
28             }
29         }
30         int res = 1;
31         double ans = 0;
32         for(i = 1; i <= (1 << n); ++i)
33             if(ans < dp[n][i])
34                 ans = dp[n][i], res = i;
35         printf("%d\n", res);
36     }
37 }

 

posted @ 2015-02-17 18:58  AC_Phoenix  阅读(149)  评论(0编辑  收藏  举报