1. 程式人生 > >【BZOJ3470】Freda’s Walk 概率與期望

【BZOJ3470】Freda’s Walk 概率與期望

space 現在 pre -c 我們 mil pop 小數 ble

【BZOJ3470】Freda’s Walk

Description

雨後的Poetic Island空氣格外清新,於是Freda和Rainbow出來散步。 Poetic Island的交通可以看作一張n個點、m 邊的有向無環圖。由於剛下過雨,每條邊都有一個積水深度,而恰好Freda 和Rainbow都喜歡踩水玩兒,於是Ta們從某個點出發,選擇走向哪條邊的概率與該邊的積水深度是成正比的。即:如果Freda和Rainbow現在在點u,點u 出發的所有邊的積水深度之和為s,從u到v的邊積水深度為w,那麽Ta們選擇走向v的概率就是 w/s。
Ta們會一直走下去,直到到達一個沒有出邊的點,那麽散步的路程長度就是走過的邊的數量。更特殊的是,Freda和Rainbow在出發之前還可以選擇一條邊,在散步過程中無視這條邊的存在(當然也可以不選擇)。請你幫忙計算一下,Ta 們從0號點出發,散步的路程長度的期望值最大是多少?

Input

第一行兩個正整數 n、m。
接下來m行每行三個整數u、v、w,表示從u到v有一條無向邊,積水深度為w。

Output

輸出Freda和Rainbow散步的路程長度的最大期望值,四舍五入保留六位小數。

Sample Input

4 5
0 1 2
0 2 1
0 3 3
1 3 1
2 3 4

Sample Output

2.000000

HINT

對於 100% 的數據,2<=n<=10000,1<=m<=100000,0<=u,v<n,1<=w<=1000。

題解:由於是DAG,所以我們先反著跑拓撲排序,求出從每個點開始走的期望步數f[i],再正著跑拓撲排序,求出從0號點走到這個點的概率p[i]。

然後枚舉刪除那條邊<a,b>。首先刪除這條邊會使答案減去p[a]*(f[b]+1),其次a的其他出邊的概率都會增加。算一下貢獻即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn=10010;
const int maxm=100010;
int n,m,cnt;
int to[maxm],next[maxm],val[maxm],head[maxn],d[maxn],s[maxn],pa[maxm],pb[maxm],pc[maxm];
double ans;
double p[maxn],f[maxn];
queue<int> q;
inline void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),m=rd();
	int i,u,a,b,c;
	memset(head,-1,sizeof(head)),cnt=0;
	for(i=1;i<=m;i++)	a=pa[i]=rd()+1,b=pb[i]=rd()+1,c=pc[i]=rd(),add(b,a,c),s[a]+=c,d[a]++;
	for(i=1;i<=n;i++)	if(!d[i])	q.push(i);
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(i=head[u];i!=-1;i=next[i])
		{
			d[to[i]]--,f[to[i]]+=(f[u]+1)*val[i]/s[to[i]];
			if(!d[to[i]])	q.push(to[i]);
		}
	}
	memset(head,-1,sizeof(head)),cnt=0;
	for(i=1;i<=m;i++)	add(pa[i],pb[i],pc[i]),d[pb[i]]++;
	p[1]=1;
	for(i=1;i<=n;i++)	if(!d[i])	q.push(i);
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(i=head[u];i!=-1;i=next[i])
		{
			d[to[i]]--,p[to[i]]+=p[u]*val[i]/s[u];
			if(!d[to[i]])	q.push(to[i]);
		}
	}
	ans=f[1];
	for(i=1;i<=m;i++)
	{
		a=pa[i],b=pb[i],c=pc[i];
		double g=(f[a]-(f[b]+1)*c/s[a])*s[a]/(s[a]-c)-f[a];
		ans=max(ans,f[1]+g*p[a]);
	}
	printf("%.6lf",ans);
	return 0;
}

【BZOJ3470】Freda’s Walk 概率與期望