poj 3071 Football(dp)

题意:给出n2个队伍,pij 表示队伍i能赢队伍j的概率,给出一个n*n2个概率矩阵,让你求出最后总赢的可能性最大的队伍。

思路:除了给出的矩阵里的数为double,这就是一个典型的dp题,不过中间要用到位运算,呃,这个真的好难理解。举个例子来说吧,n = 3 。

 (1)    1 2  3 4  5 6  7 8  (假设这一轮比赛后,获胜的队伍为 1 , 3 , 5 , 7 )

 (2)    1  3   5  7   (假设这一轮比赛后获胜的队伍是 1 , 5 )

 (3)    1  5    (这一轮比赛后获胜的队伍只能是 1 或 5 )

所以,要想得出最后获胜的队伍,要比n轮,dp[i][j] 表示第i轮j获胜的概率,则,在第一轮中队伍1获胜的概率与队伍2 有关。队伍3与队伍4 有关,以此类推;第二轮中,队伍1获胜的概率是在第1轮中获胜的基础上,与队伍3、4中获胜的队伍有关,由此可以退推出,dp[i][j] = dp[i-1][j] * Σdp[i-1][k] * p[j][k] ; k 表示所有可能与队伍j比赛的队伍。

代码:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <math.h>
#define  N 310
#define  M 10
using namespace std ;

double dp[M][N] , p[N][N] ;
int n , m ;

int powx ( int x )
{
    int s = 1 ;
    while ( x-- )
    {
        s *= 2 ;
    }
    return s ;
}

int main()
{
    int i , j , k ;

    while ( scanf ( "%d" , &m ) , m != -1 )
    {
        n = powx ( m ) ;
        for ( i = 0 ; i < n ; i++ )
        {
            for ( j = 0 ; j < n ; j++ )
            scanf ( "%lf" , &p[i][j] );
        }

        //初始化
        for ( i = 0 ; i < n ; i++ )
        dp[0][i] = 1.0 ;

        for ( i = 1 ; i <= m ; i++ )
        {
            for ( j = 0 ; j < n ; j++ )
            {
               dp[i][j] = 0.0 ;
               for ( k = 0 ; k < n ; k++ )
                   if(((k>>(i-1))^1) == j>>(i-1))//判断队伍k是否可能与队伍j比赛
                   {
                       //cout<<k<<" ";
                       dp[i][j] += dp[i-1][k] * p[j][k] ;
                   }
                   dp[i][j] *= dp[i-1][j] ;
                   cout<<endl;
            }
        }

        double maxx = -1.0 ;
        int pos ;
        for ( i = 0 ; i < n ; i++ )
        {
            if ( dp[m][i] > maxx )
            {
                maxx = dp[m][i] ;
                pos = i + 1 ;
            }
        }

        printf ( "%d\n" , pos );
    }
    return 0 ;
}

其中代码中判断条件是参考题解的来的,自己写了个测试程序,来看它的运行结果,

代码:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <math.h>
using namespace std ;

int main()
{
    int i , j , k , n , m ;

    while ( scanf ( "%d" , &m ) != EOF )
    {
        n =  ( int ) pow ( 2.0 , 1.0 * m );

        for ( i = 1 ; i <= m ; i++ )
        {
            printf ( "第%d轮:\n" , i ) ;
            for ( j = 0 ; j < n ; j++ )
            {
                printf ( "与队伍 %d 比赛的有:" , j + 1 ) ;
                for ( k = 0 ; k < n ; k++ )
                {
                    if ( ( ( k >> ( i - 1 )) ^ 1 ) == j >> ( i - 1 ))
                    printf ( " %d" , k );
                }
                printf ( "\n" );
            }
        }
    }
    return 0 ;
}

可是还是不能很灵活的运用位运算~唉,慢慢研究吧。。。

posted @ 2012-08-20 21:16  Misty_1  阅读(142)  评论(0编辑  收藏  举报