因为是二叉结构,,所以会比较容易想到树型的结构,所以自然想到树型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,1int 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;
}