因为是二叉结构,,所以会比较容易想到树型的结构,所以自然想到树型dp
然而怎么设dp呢,,我是这样的
dp[MX<<2][MX],第一个表示二叉树的节点编号,第二个表示i在这个节点所对应的区间中赢到最后的概率
节点对应的区间,和线段树的写法是一样的,,其实就是在线段树的build的代码上,把push_up改了一下而已,其他的都差不多
对于某个节点,先求出左右节点的概率情况,然后把左右节点的答案合并
在节点对应的区间内,枚举i赢了
如果i在左树,那么就枚举右树中有哪些人j。然后积累i赢所有的j的概率,最后乘上i在左树中赢到最后的概率
这样就把左右的答案合并了,然后再回溯到父节点继续就可以了
说起来很玄,,其实代码很简单...
#include<cstdio> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<functional> #include<algorithm> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MX = 150 + 5; const int INF = 0x3f3f3f3f; #define For(i,x,y) for(int i=x;i<=y;i++) #define Mem(x,y) memset(x,y,sizeof(x)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define root 1,n,1 int n; double A[MX][MX]; double dp[MX << 2][MX]; void solve(int l, int r, int rt) { if(l == r) { dp[rt][l] = 1; return; } int m = (l + r) >> 1; solve(lson); solve(rson); For(x, l, r) { if(x <= m) { For(i, m + 1, r) { dp[rt][x] += dp[rt << 1 | 1][i] * A[x][i]; } dp[rt][x] *= dp[rt << 1][x]; } else { For(i, l, m) { dp[rt][x] += dp[rt << 1][i] * A[x][i]; } dp[rt][x] *= dp[rt << 1 | 1][x]; } } } int main() { //freopen("input.txt", "r", stdin); int n; while(~scanf("%d", &n), n >= 0) { Mem(dp, 0); n = 1 << n; For(i, 1, n) { For(j, 1, n) { scanf("%lf", &A[i][j]); } } solve(root); double Max = 0; int ans; For(i, 1, n) { if(dp[1][i] > Max) { Max = dp[1][i]; ans = i; } } printf("%d\n", ans); } return 0; }