zoukankan      html  css  js  c++  java
  • 【BZOJ3470】Freda’s Walk 概率与期望

    【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;
    }
  • 相关阅读:
    页面抛出的"Unable to validate data"错误
    oracle的sqlnet.ora,tnsnames.ora,listener.ora三个配置文件 water
    Win7下完全卸载Oracle 11g water
    抛出多个异常 water
    【转】有关Oracle随机字符串的生成方法及具体应用 water
    【转】oracle 中随机取一条记录的两种方法 water
    【转】Oracle索引列NULL值引发执行计划该表的测试示例 water
    Oracle 取随机数 water
    dbms_output.put_line长度限制问题 water
    oracle 监听启动、停止、查看命令 water
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7965528.html
Copyright © 2011-2022 走看看