• [BZOJ3470]Freda’s Walk


    bzoj

    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 le n le 10000,1le mle 100000,0 le u,v<n,1le wle1000)

    sol

    先正反建图跑出从每个点出发的期望行走步数(f_i)和从起点出发到达每个点的概率(p_i)
    枚举删掉一条边((u,v)),那么(f_u)中相应的会减少(f_v)的贡献,但其他出边贡献的比例则增大了,又因为(f_i)的一个变化量(Delta)导致的(f_1)的变化量是(p_iDelta),所以可以(O(1))计算删掉每条边对答案的影响,取(max)即可。

    code

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 2e5+5;
    int n,m,to[N],nxt[N],ww[N],hd1[N],hd2[N],cnt,du[N],sum[N];
    double p[N],f[N],ans;
    queue<int>Q;
    void link(int v,int w,int &hd){
    	to[++cnt]=v;nxt[cnt]=hd;ww[cnt]=w;hd=cnt;
    }
    int main(){
    	n=gi();m=gi();
    	for (int i=1;i<=m;++i){
    		int u=gi()+1,v=gi()+1,w=gi();
    		link(v,w,hd1[u]);link(u,w,hd2[v]);sum[u]+=w;
    	}
    	for (int i=1;i<=n;++i)
    		for (int e=hd1[i];e;e=nxt[e])
    			++du[to[e]];
    	for (int i=1;i<=n;++i) if (!du[i]) Q.push(i);
    	p[1]=1;
    	while (!Q.empty()){
    		int u=Q.front();Q.pop();
    		for (int e=hd1[u];e;e=nxt[e]){
    			p[to[e]]+=p[u]*ww[e]/sum[u];
    			if (!--du[to[e]]) Q.push(to[e]);
    		}
    	}
    	for (int i=1;i<=n;++i)
    		for (int e=hd2[i];e;e=nxt[e])
    			++du[to[e]];
    	for (int i=1;i<=n;++i) if (!du[i]) Q.push(i);
    	while (!Q.empty()){
    		int u=Q.front();Q.pop();
    		for (int e=hd2[u];e;e=nxt[e]){
    			f[to[e]]+=(f[u]+1)*ww[e]/sum[to[e]];
    			if (!--du[to[e]]) Q.push(to[e]);
    		}
    	}
    	for (int i=1;i<=n;++i)
    		for (int e=hd1[i];e;e=nxt[e]){
    			double tmp=(f[i]-(f[to[e]]+1)*ww[e]/sum[i])*sum[i]/(sum[i]-ww[e]);
    			ans=max(ans,(tmp-f[i])*p[i]);
    		}
    	printf("%.6lf
    ",ans+f[1]);
    	return 0;
    }
    
  • 相关阅读:
    [转]Hibernate Session各种状态转换方法分析
    Hibernate3回顾-4-事务和并发管理
    Hibernate3回顾-3-Session管理
    Hibernate3回顾-2-相关概念
    [转]oracle for update和for update nowait的区别
    数组
    Android 调用webservice faultactor 错误
    Java "==和equals区别" 示例
    Java "==和equals区别"
    Java "double字符串转数字"
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9268955.html
Copyright © 2020-2023  润新知