poj 3071 Football(dp)
题意:给出n2个队伍,pij 表示队伍i能赢队伍j的概率,给出一个n2 *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 ; }
可是还是不能很灵活的运用位运算~唉,慢慢研究吧。。。