题意:
有(n(n leq 18))个人打擂台赛,编号从(1)到(n),主角是(1)号。
一开始主角先选一个擂主,和一个打擂的人。
两个人之中胜的人留下来当擂主等主角决定下一个人打擂,败的人退出比赛,直到比赛只剩一个人。
已知任意两人之间决胜的胜率(P_{ij}),求主角最终能够获胜的概率。
分析:
设(d(S, i))表示存活的人的集合为(S),当前擂主为(i in S),主角获胜的概率。
为了方便我们把编号设为(0 sim n-1),递推边界(d(1,0)=1)。
考虑(d(S,i)),枚举下一个要打擂的人(k in S):
- (P_{ij})的概率(i)战胜(j),擂主为(i),状态转移到(d(S-j,i))
- (P_{ji})的概率(j)战胜(i),擂主为(j),状态转移到(d(S-i,j))
因为主角可以决定打擂人选(j),所以(d(S,i)=max{ P_{ij}d(S-j,i) + P_{ji}d(S-i,j) })
最后枚举最开始的擂主,选一个最大值就是答案。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
double p[18][18], d[1 << 18][18];
int main()
{
int n; scanf("%d", &n);
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++) scanf("%lf", &p[i][j]);
d[1][0] = 1;
for(int S = 3; S < (1 << n); S += 2) {
for(int i = 0; i < n; i++) if(S&(1<<i)) {
for(int j = 0; j < n; j++) if(j != i && (S&(1<<j))) {
d[S][i] = max(d[S][i], p[i][j]*d[S^(1<<j)][i] + p[j][i]*d[S^(1<<i)][j]);
}
}
}
double ans = 0;
for(int i = 0; i < n; i++) ans = max(ans, d[(1<<n)-1][i]);
printf("%.15f
", ans);
return 0;
}