「CF678E Another Sith Tournament」题解
Description
如果你做过 CF16E 和 CF540D 的话,那么恭喜你,这道题你 A 了。
因为1是一定在最后胜利的,所以我们考虑倒推,又因为 \(n\leq18\),容易想到状压。
设 \(dp[i]({i|i\in [1,2^n-1]})\) 表示目前存活的人的集合为 i 时,1获胜的概率,\(p[i][j]\) 表示 \(i\) 战胜 \(j\) 的概率。
易知 \(dp[1]=1\)。
这个思路和 CF540D 类似。
因为我们需要保证1能存活到最后且是从1存活开始转移,所以当前方案的概率仅有可能会从死掉1个人后1存活的概率转移来。
这个过程其实是记忆化搜索,只不过我们把它写成了 \(\operatorname{DP}\) 的形式。
那么转移方程就清晰了
\[dp[i]=\max(dp[i-2^k]\times p[j][k],dp[i-2^j]\times p[k][j])
\]
为什么比最大值呢?因为1可以操作比赛,故而会选择使得自己胜率最高的比赛顺序。
Code:
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=25;
const int MAXM=3e5+5;
int n;
double p[MAXN][MAXN];
double dp[MAXM];
int main(){
scanf("%d",&n);
for (int i=0;i<n;i++){
for (int j=0;j<n;j++){
scanf("%lf",&p[i][j]);
}
}
int k=(1<<n);
dp[1]=1;
for (int kk=2;kk<k;kk++){
for (int i=0;i<n;i++){
if(!(kk&(1<<i)))
{
continue;
}
for (int j=i+1;j<n;j++){
if (!(kk&(1<<j)))
{
continue;
}
dp[kk]=max(dp[kk],dp[kk^(1<<i)]*p[j][i]+dp[kk^(1<<j)]*p[i][j]);
}
}
}
printf("%.7lf\n",dp[k-1]);
return 0;
}
\(\Bbb{End.}\)
\(\Bbb{Thanks} \space \Bbb{For} \space \Bbb{Reading.}\)
本文来自博客园,作者:{StranGePants},转载请注明原文链接:https://www.cnblogs.com/StranGePants/p/15354580.html