zoukankan      html  css  js  c++  java
  • 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 ;
    }

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

  • 相关阅读:
    P2420 让我们异或吧(倍增)
    bzoj题目分类
    hash练习们
    bzoj1433[ZJOI2009]假期的宿舍(匈牙利)
    bzoj2427:[HAOI2010]软件安装(Tarjan+tree_dp)
    bzoj2730矿场搭建(Tarjan割点)
    codevs4511信息传递(Tarjan求环)
    进入js
    css层叠样式表
    HTML超文本标记语言
  • 原文地址:https://www.cnblogs.com/misty1/p/2648106.html
Copyright © 2011-2022 走看看