CF605E Intergalaxy Trips

题解

这道题目的题解也太拉了吧。

我感觉我现在已经明白了它的真实奥义了!!!

首先我们可以考虑逆序思考,即 \(E_i\) 表示第 \(i\) 个点到第 \(n\) 个点的期望天数,在不考虑自环的情况下。

我们再令一个点确定要走的边都不走的概率是 \(P_i\) ,那么易得该点期望等待天数就是 \(\frac{1}{1-P_i}\)

我们需要明白的是,如果我们已知期望值前若干小的点的期望值 \(E_i\) ,我们就可以利用这几个点的值来计算出剩下的点往这几个点的走的期望 \(E‘_j\) 是多少,注意,这里的期望是仅仅走向已知点的期望值,并未考虑未知的点两两之间的影响。

我们现在考虑未知点的两两之间对于期望的影响。由于我们已知的期望值 \(E_i\) 都是前若干小的,所以我们必然可以得到,未知的点的此时计算出来的期望值 \(E‘_j\) ,如果 \(j_1\rightarrow j_2\) 的转移是有贡献的,必然此时的 \(E‘_{j_1}>E‘_{j_2}\) ,这个我们可以通过转移的式子来得到。

\[E_u=\sum_v\frac{E_v}{1-P_v}\cdot p_{u,v}\prod_{E_w<E_v}(1-p_{u,w}) \]

我们考虑相反的操作,必然会使得 \(E_{j_1}\) 增大,这并不优。

然后我们就考虑一直执行这样的步骤就行了。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
int n;bool tag[N];
double E[N],f[N],p[N][N];
int main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j)
		scanf("%lf",&p[i][j]),p[i][j]/=100;
	}
	tag[n]=true,E[n]=0;
	for(int i=1;i<n;++i) E[i]=1,f[i]=1-p[i][n];
	for(int i=1;i<n;++i){
		int pos=-1;double Min=1e9+7;
		for(int j=1;j<=n;++j){
			if(tag[j]) continue;
			if(Min>E[j]/(1-f[j]))
			Min=E[j]/(1-f[j]),pos=j;
		}
		tag[pos]=true;
		// printf("%d %.7lf\n",pos,E[pos]/(1-f[pos]));
		for(int j=1;j<=n;++j){
			if(tag[j]) continue;
			E[j]+=E[pos]/(1-f[pos])*p[j][pos]*f[j],f[j]*=1-p[j][pos];
		}
	}
	return printf("%.7lf\n",E[1]/(1-f[1])),0;
}

CF605E Intergalaxy Trips

上一篇:CentOS7安装Nginx


下一篇:Unicode 和 UTF-8 有何区别