概述
题意简述
有 n ( < = 18 ) n(<=18) n(<=18)个鱼,其中第 i i i个鱼把第 j j j个与吃掉的概率是 a [ i ] [ j ] a[i][j] a[i][j],保证 a [ i ] [ j ] + a [ j ] [ i ] = 1 , a [ i ] [ i ] = 0 a[i][j]+a[j][i]=1,a[i][i]=0 a[i][j]+a[j][i]=1,a[i][i]=0。会有 n − 1 n-1 n−1轮,每一轮会等概率随机选择两个鱼来比♂拼,然后直到最后只剩下一个鱼。对于每个鱼,求最后剩下它的概率。
顺便膜鱼,鱼tql%%%
思路框架
状压 D P DP DP。对于每个状态,枚举已有的鱼,枚举上一次被吃掉的鱼,加一下。
具体思路
设 d p [ S ] dp[S] dp[S]表示剩下活着的鱼状态为 S S S的概率。那么,我们在 S S S中找到一条鱼 k k k,设它为上一次获胜的。那么上一次死掉的肯定不在 S S S里面了,就到 S S S外面去找一条上一次死掉的鱼 j j j。设 S S S中包含 C C C条鱼,那么 d p [ S ] + = d p [ S p l u s j ] × 1 C ( C + 1 ) / 2 × a [ k ] [ j ] dp[S]+=dp[S plus j]times frac{1}{C(C+1)/2} times a[k][j] dp[S]+=dp[S plus j]×C(C+1)/21×a[k][j]。其中 S p l u s j S plus j S plus j表示 S S S中加入 j j j,用位运算表示为 [ S ∣ ( 1 ≪ j ) ] [S|(1ll j)] [S∣(1≪j)]。 1 C ( C + 1 ) / 2 frac{1}{C(C+1)/2} C(C+1)/21 是选择 j j j 和 k k k出来比♂拼的概率, a [ k ] [ j ] a[k][j] a[k][j]是 k k k把 j j j吃掉的概率。
然后转移一下。答案就是只选i的状态。
代码:
#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define N 18
#define real double
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
int n;
real a[N][N];
void Input()
{
scanf("%d",&n);
F(i,0,n-1) F(j,0,n-1) scanf("%lf",&a[i][j]);
}
real dp[1<<N];
void Soviet()
{
int All=(1<<n)-1;
dp[All]=1.00;
D(i,All-1,0)
{
real cnt=(real)__builtin_popcount(i);
F(j,0,n-1) if (!((1<<j)&i))
{
F(k,0,n-1) if ((1<<k)&i)
{
real P=1/(cnt*(cnt+1)/2.00);
dp[i]+=dp[i|(1<<j)]*a[k][j]*P;
}
}
}
F(i,0,n-1)
{
printf("%.6f ",dp[(1<<i)]);
}putchar('n');
}
#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
}
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}
最后问一下,那个标题为什么显示不出来啊,有没有人救救我。。。
最后
以上就是潇洒耳机为你收集整理的Codeforces 16E Fish 题解的全部内容,希望文章能够帮你解决Codeforces 16E Fish 题解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复