POJ 3071 Football

1 题目大意

给定 $2^n$ 个整数,从 $1$ 到 $2^n$ 编号

给定 $p_{i,j}(1\leq i \leq n, 1 \leq j \leq n)$

定义一次操作为

选中 $2k$ 和 $2k+1$ ( $0 \leq k, k \in Z, 2k+1 \leq n$ )
其中有 $p_{2k,2k+1}$ 的概率选中 $2k$
其中有 $p_{2k+1,2k}$ 的概率选中 $2k+1$

把所有选择的数字组成一个新的数列,大小为 $\frac{n}{2}$

显然最后会只剩 $1$ 个数字

问剩哪个数字的概率最大

2 思路

这东西显然是个满二叉树,大力 dfs,每次分成两半

每次向上的时候,把两边概率和一下,就没事了

3 Code

#include <cstdio>

const int N = 1100;

int n;
double p[N][N];
double f[N];

void dfs( int left, int rig ) {
    if( left == rig ) {
        f[left] = 1;
        return ;
    }
    int mid = ( left + rig ) >> 1;
    dfs( left, mid );
    dfs( mid + 1, rig );

    double la[N];
    for( int i = left; i <= rig; i ++  )
        la[i] = f[i];

    for( int i = left; i <= mid; i ++ ) {
        double cur = f[i];
        f[i] = 0;
        for( int j = mid + 1; j <= rig; j ++ ) {
            f[i] += ( cur * la[j] * p[i][j] );
        }
    }
    for( int i = mid + 1; i <= rig; i ++ ) {
        double cur = f[i];
        f[i] = 0;
        for( int j = left; j <= mid; j ++ ) {
            f[i] += ( cur * la[j] * p[i][j] );
        }
    }
}

int main() {
#ifdef woshiluo
    freopen( "poj.3071.in", "r", stdin );
    freopen( "poj.3071.out", "w", stdout );
#endif
    while(1) {
        scanf( "%d", &n );
        if( n == -1 ) 
            break;
        n = ( 1 << n );
        for( int i = 1; i <= n; i ++ ) {
            for( int j = 1; j <= n; j ++  ){
                scanf( "%lf" ,&p[i][j] );
            }
        }

        dfs( 1, n );

        int max_id = 0;
        for( int i = 1; i <= n; i ++ ) {
            if( f[i] > f[ max_id ] )
                max_id = i;
        }

        printf( "%d\n", max_id );
    }
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

message
account_circle
Please input name.
email
Please input email address.
links

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据