现在的位置: 首页 > 综合 > 正文

【HDU】4870 Rating 概率DP

2017年11月20日 ⁄ 综合 ⁄ 共 1261字 ⁄ 字号 评论关闭

传送门:【HDU】4870 Rating

题目分析:虽然题目看起来是两个帐号紧密相联的,但是由于每次都是只选择rating低的去打,其实可以将这个过程看成:先将一个号打到19级,然后再将一个号打到20级。

这样我们就列一个状态转移方程:dp[ i ] = p * dp[i + 1] + ( 1 - p ) * dp[i - 2] + 1。

然后做两次高斯消元(一次19,一次20 )即可。注意细节问题。

代码如下:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;


#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define REV( i , n ) for ( int i = n - 1 ; i >= 0 ; -- i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define FOV( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define REPF( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define REPV( i , a , b ) for ( int i = a - 1 ; i >= b ; -- i )

#define CLR( a , x ) memset ( a , x , sizeof a )

const int MAXN = 22 ;
const double eps = 1e-10 ;

double p ;
double a[MAXN][MAXN] ;
int sgn ( double x ) {
	return ( x > eps ) - ( x < -eps ) ;
}

void guass ( int n , int m ) {
	for ( int r = 0 , c = 0 ; r <= n , c <= m ; ++ r , ++ c ) {
		int tmp = r ;
		FOR ( i , r + 1 , n )
			if ( sgn ( fabs ( a[i][c] ) - fabs ( a[tmp][c] ) ) > 0 )
				tmp = i ;
		if ( sgn ( a[tmp][c] ) == 0 ) {
			--r ;
			continue ;
		}
		if ( tmp != r )
			FOR ( i , c , m )
				swap ( a[r][i] , a[tmp][i] ) ;
		FOV ( i , m , c )
			a[r][i] /= a[r][c] ;
		FOR ( i , 0 , n )
			if ( sgn ( a[i][c] ) && i != r )
				FOV ( j , m , c )
					a[i][j] -= a[i][c] * a[r][j] ;
	}
}

double solve ( int n ) {
	CLR ( a , 0 ) ;
	FOR ( i , 0 , n ) {
		if ( i == 0 ) {
			a[i][i] = p ;
			a[i][i + 1] = -p ;
			a[i][n + 1] = 1 ;
		}
		else if ( i == 1 ) {
			a[i][i] = 1 ;
			a[i][i - 1] = p - 1 ;
			a[i][i + 1] = -p ;
			a[i][n + 1] = 1 ;
		}
		else if ( i != n ) {
			a[i][i] = 1 ;
			a[i][i + 1] = -p ;
			a[i][i - 2] = p - 1 ;
			a[i][n + 1] = 1 ;
		}
		else {
			a[i][i] = 1 ;
		}
		
	}
	guass ( n , n + 1 ) ;
	return a[0][n + 1] ;
}


int main () {
	while ( ~scanf ( "%lf" , &p ) )
		printf ( "%.6f\n" , solve ( 19 ) + solve ( 20 ) ) ;
	return 0 ;
}

抱歉!评论已关闭.