【XSY1596】旅行 期望DP

题目大意

  有\(m\)个游客, 他们都依次访问城市\(1,2,3,\ldots,n\), 第\(i\)个游客到达任意一个城市后有\(p_i\)的概率会停下, 不再继续前行

  设\(c_i\)个乘客经过了城市\(i\),则第\(i\)个人经过第\(j\)个城市时的快乐值是\(\frac{c_j+1}{c_{j-1}}h_{i,j}\)

  求每个人的快乐值之和的期望

  \(m,n\leq16\)

题解

  枚举城市\(x\)和经过当前城市的人的状态\(s\)

  设当前状态的人数为\(cnt\),出现概率为\(ps\),所有经过当前城市的人的\(p_i\)的和为\(pn\)

  枚举每个人\(i\)\(i\)\(x+1\)城市对答案的贡献是

\[\frac{\text{当前状态出现概率$\times$第$i$个人走到下一个城市的概率$\times($其他人走到下一个城市的概率$+$第$i$个人一定会走到下一个城市$)$}}{\text{经过$i$城市的人数}}h_{i,x+1} \]

\[\frac{ps\times p_i\times (pn-p_i+1)}{cnt}h_{i,x+1} \]

  时间复杂度:\(O(nm2^m)\)

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
double p[20];
double f[20][20];
double h[20][20];
int main()
{
//	freopen("b.in","r",stdin);
	int n,m;
	scanf("%d%d",&m,&n);
	int i;
	for(i=1;i<=m;i++)
		scanf("%lf",&p[i]);
	int j;
	for(i=1;i<=m;i++)
	{
		f[i][1]=1;
		for(j=2;j<=n;j++)
			f[i][j]=f[i][j-1]*p[i];
	}
	double ans=0;
	for(i=1;i<=m;i++)
		for(j=1;j<=n;j++)
		{
			scanf("%lf",&h[i][j]);
			ans+=f[i][j]*h[i][j];
		}
	int s;
	for(i=1;i<=n-1;i++)
		for(s=1;s<(1<<m);s++)
		{
			double ps=1,sum=0,pn=0;
			int cnt=0;
			for(j=1;j<=m;j++)
				if(s&(1<<(j-1)))
				{
					ps*=f[j][i];
					cnt++;
					pn+=p[j];
				}
				else
					ps*=1-f[j][i];
			for(j=1;j<=m;j++)
				if(s&(1<<(j-1)))
					sum+=p[j]*h[j][i+1]*(pn-p[j]+1);
			ans+=ps*sum/cnt;
		}
	printf("%.10lf\n",ans);
	return 0;
}
posted @ 2018-03-05 21:02  ywwyww  阅读(207)  评论(1编辑  收藏  举报