Educational Codeforces Round 13 E. Another Sith Tournament 概率dp+状压
题目链接:
题目
E. Another Sith Tournament
time limit per test2.5 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
问题描述
The rules of Sith Tournament are well known to everyone. n Sith take part in the Tournament. The Tournament starts with the random choice of two Sith who will fight in the first battle. As one of them loses, his place is taken by the next randomly chosen Sith who didn't fight before. Does it need to be said that each battle in the Sith Tournament ends with a death of one of opponents? The Tournament ends when the only Sith remains alive.
Jedi Ivan accidentally appeared in the list of the participants in the Sith Tournament. However, his skills in the Light Side of the Force are so strong so he can influence the choice of participants either who start the Tournament or who take the loser's place after each battle. Of course, he won't miss his chance to take advantage of it. Help him to calculate the probability of his victory.
输入
The first line contains a single integer n (1 ≤ n ≤ 18) — the number of participants of the Sith Tournament.
Each of the next n lines contains n real numbers, which form a matrix pij (0 ≤ pij ≤ 1). Each its element pij is the probability that the i-th participant defeats the j-th in a duel.
The elements on the main diagonal pii are equal to zero. For all different i, j the equality pij + pji = 1 holds. All probabilities are given with no more than six decimal places.
Jedi Ivan is the number 1 in the list of the participants.
输出
Output a real number — the probability that Jedi Ivan will stay alive after the Tournament. Absolute or relative error of the answer must not exceed 10 - 6.
样例
input
3
0.0 0.5 0.8
0.5 0.0 0.4
0.2 0.6 0.0
output
0.680000000000000
题意
n个人,每次两个人决斗,输的退场,赢的继续和下一个人打,你可以决定开始决斗的两人和每局上场和赢的人打的那个人。现在你是第0号,问你赢得比赛的最大概率是多少。也就是说在某一固定的上场顺序下,能赢的概率最大,求这个最大概率。
题解
dp[i][j]表示现在还活着的人是状态i(为1的代表活着),在台上的人是j,0号能赢的最大概率。dp[1][0]=1。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 18;
double dp[1 << maxn][maxn];
double p[maxn][maxn];
int n;
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
scanf("%lf", &p[i][j]);
}
}
memset(dp, 0, sizeof(dp));
dp[1][0] = 1;
for (int i = 0; i < (1 << n); i++) {
for (int j = 0; j < n; j++) if(i&(1<<j)){
for (int k = 0; k < n; k++)if (i&(1 << k) && k != j) {
dp[i][j] = max(dp[i][j], p[j][k] * dp[i ^ (1 << k)][j] + p[k][j] * dp[i ^ (1 << j)][k]);
}
}
}
double ans = 0;
for (int i = 0; i < n; i++) {
ans = max(ans, dp[(1 << n) - 1][i]);
}
printf("%.15lf\n", ans);
return 0;
}