codeforces 605E

luogu鏈接

解法

(好像在哪裏見過幾乎一樣的問題?)
考慮這種圖上的期望一般倒着算,所以可以從終點反推回起點。
然後考慮我們更新點到終點的距離的過程,我們每次選出一個目前到終點距離最近的點,用它去更新和它相鄰的點的距離,這個是也是最短路的思想。由於沒有負權邊,所以考慮用迪傑斯特拉

轉移方程
d[u]=vd[v]p[u][v](1pr[u]),dd[u]=\sum_v d[v]*p[u][v]*(1-pr[u]),更新的時候按d從小到大的順序
d[i]ind[i]:i到n的最小期望
pr[i]idj)pr[i]:i已經轉移走的概率(dj更新的時候需要)
sum[i]isum[i]:已經計算過的到i的期望

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char c=getchar();int t=0,f=1;
	while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
	while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int n,vis[1005],a[1005];
double p[1005][1005],d[1005],pr[1005],sum[1005];
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		int x=0;
		sum[i]=pr[i]=1.0;
		for(int j=1;j<=n;j++){
			x=read();
			p[i][j]=x*0.01;
		}
	}
	vis[n]=1;
	a[1]=n;d[0]=1e18;
	for(int i=2;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(vis[j])continue;
			sum[j]+=d[a[i-1]]*p[j][a[i-1]]*pr[j];
			pr[j]*=(1-p[j][a[i-1]]),d[j]=sum[j]/(1-pr[j]);
		}
		int pos=0;
		for(int j=1;j<=n;j++){
			if((!vis[j])&&(d[j]<d[pos]))pos=j;
		}
		vis[pos]=1;a[i]=pos;
	}
	printf("%.10lf\n",d[1]);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章