POJ--3071(概率DP)
2014-12-29 22:14:20
思路:这道题我醉了....
思路很巧妙,用dp[i][j]来表示第i轮j赢的概率,那么就要让第i-1轮后j仍然存活。
有转移方程:dp[i][j] = Sima(dp[i - 1][j] * dp[i - 1][k] * P[j][k],(P[j][k]表示j打败k的概率,要注意这个k的选择,这里很巧妙地运用了位运算,算出所有能在第i轮和j对位的k,
用(((j >> (i - 1)) ^ 1) == (k >> (i - 1)),来判断是否处于同一颗子树,且有机会使得j和k在第i轮对位,注意人的下标从0开始!,思考。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <iostream> 11 #include <algorithm> 12 using namespace std; 13 #define lp (p << 1) 14 #define rp (p << 1|1) 15 #define getmid(l,r) (l + (r - l) / 2) 16 #define MP(a,b) make_pair(a,b) 17 typedef long long ll; 18 typedef unsigned long long ull; 19 const int INF = 1 << 30; 20 21 int N; 22 double dp[10][150],P[150][150]; 23 24 int main(){ 25 while(scanf("%d",&N) != EOF){ 26 if(N == -1) 27 break; 28 int sz = 1 << N; 29 for(int i = 0; i < sz; ++i) 30 for(int j = 0; j < sz; ++j) 31 scanf("%lf",&P[i][j]); 32 memset(dp,0,sizeof(dp)); 33 for(int i = 0; i < sz; ++i) 34 dp[0][i] = 1.0; 35 for(int i = 1; i <= N; ++i){ 36 for(int j = 0; j < sz; ++j){ 37 for(int k = 0; k < sz; ++k){ 38 if(((j >> (i - 1)) ^ 1) == (k >> (i - 1))) 39 dp[i][j] += dp[i - 1][j] * dp[i - 1][k] * P[j][k]; 40 } 41 } 42 } 43 int ans = 0; 44 for(int i = 1; i < sz; ++i) 45 if(dp[N][i] > dp[N][ans]) 46 ans = i; 47 printf("%d\n",ans + 1); 48 } 49 return 0; 50 } 51