1. 程式人生 > 其它 >CF605E Intergalaxy Trips

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;
}