题解
题意:1~n号斗殴,赢的人和剩下未出场过的人继续斗殴,1号可以自由安排出场顺序,问1号活到最后的概率
之前看错题意了,想了半天概率为啥是max而不是求和,
出场顺序会影响1最终获胜的概率,因为顺序是自己定的,而1号又会为了能够活到最后,肯定是采用获胜概率最大的出场顺序,所以最终的概率是定的,只是不知道是何种方式产生的,就像背包问题只需要知道最大价值而不需要具体方案,用 max 就能找到最优解
然后看样例:
如果1号第一轮出场并苟到了最后 (两种顺序:一开始 {1,2} 打,赢得人和3打 or 一开始 {1,3} 打,赢得人和2打)
这两种顺序的概率都是一样的
P
=
p
1
,
2
×
p
1
,
3
=
0.4
P=p_{1,2}\times p_{1,3}=0.4
P=p1,2×p1,3=0.4
如果1号第二轮出场并苟到了最后 (一种顺序:一开始 {2,3} 打,赢的人和1打)
- 如果第一轮2号获胜, P = p 2 , 3 ∗ p 1 , 2 = 0.2 P=p_{2,3}*p_{1,2}=0.2 P=p2,3∗p1,2=0.2
- 如果第一轮3号获胜, P = p 3 , 2 ∗ p 1 , 3 = 0.48 P=p_{3,2}*p_{1,3}=0.48 P=p3,2∗p1,3=0.48
所以概率 P = 0.68 P=0.68 P=0.68,因此很明显,1号会选择这种顺序
由于如果按照顺序正推,在1号出场之前,某一场的输赢会导致后面的概率的不同,如果dfs会产生一棵庞大的顺序树(n=18 > 11),空间不允许
因此这里采用逆推:顺序从最后往前递推,往代表存活的集合里加人,能加入集合的人,都是打过擂的
用 f s t a t e f_{state} fstate 表示 状态为 s t a t e state state 时1活到最后的概率,
一开始只有最终存活的1号,然后不停的往里面加前一轮获胜的人,由于前一轮比赛的只会有两个人,因此概率为两者状态发生的概率之和
用这种方式解释样例:
最后倒数第二个存活的人可能是2号,也可能是3号,但是不管怎么样,都是 {{2,3},1} 这种顺序产生的,
因此 f 111 ( 3 , 2 , 1 ) = f 011 ( 2 , 1 ) × p 3 , 2 + f 101 ( 3 , 1 ) × p 2 , 3 f_{111(3,2,1)}=f_{011(2,1)}\times p_{3,2}+f_{101(3,1)}\times p_{2,3} f111(3,2,1)=f011(2,1)×p3,2+f101(3,1)×p2,3
代码
#include <bits/stdc++.h>
using namespace std;
int n, m, K;
double p[20][20], f[(1 << 19)];
int main() {
ios::sync_with_stdio(0);
cin >> n;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> p[i][j];
}
}
f[1] = 1.0;
int lim = 1 << n;
for (int sta = 1; sta < lim; ++sta) {
for (int i = 0; i < n; ++i) {
if (sta >> i & 1) {
for (int j = 0; j < n; ++j) {
if (sta >> j & 1)
f[sta] = max(f[sta],
f[sta ^ (1 << i)] * p[j][i] + f[sta ^ (1 << j)] * p[i][j]);
}
}
}
}
cout << f[lim - 1] << endl;
return 0;
}