您的位置:首页 > 其它

Codeforces 678E Another Sith Tournament 状压DP

2016-06-15 15:13 232 查看

题意:

有\(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\n", ans);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: