• [bzoj3470]Freda’s Walk【概率与期望dp】


    【题目链接】
      https://www.lydsy.com/JudgeOnline/problem.php?id=3470
    【题解】
      正着做一遍求出从一号点到每个点的概率g[i]
      倒着做一遍求出每个点开始向后走期望走多远f[i]
      然后考虑去除一个点i的一条出边后的影响,显然就是f[i]的变化量乘以到达这个点的概率,而概率是不变的,还是g[i]
      

    # include <bits/stdc++.h>
    # define    N       200010      
    using namespace std;
    struct Edge{
        int data,next,vote;
    }e[N];
    int head[N],n,m,place,tag[N],p[N];
    double f[N],cnt[N],g[N],sum[N],num[N],ans,tot;
    int read(){
        int tmp=0, fh=1; char ch=getchar();
        while (ch<'0'||ch>'9') {if (ch=='-') fh=-1; ch=getchar();}
        while (ch>='0'&&ch<='9') {tmp=tmp*10+ch-'0'; ch=getchar();}
        return tmp*fh;
    }
    void build(int u, int v, int w){
        e[++place].data=v; e[place].next=head[u]; head[u]=place; 
        e[place].vote=w; tag[v]++;
    }
    void tuopu(){
        int pl=1, pr=0;
        for (int i=1; i<=n; i++)
            if (tag[i]==0) p[++pr]=i;
        while (pl<=pr){
            int x=p[pl++];
            for (int ed=head[x]; ed!=0; ed=e[ed].next){
                tag[e[ed].data]--;
                if (tag[e[ed].data]==0) p[++pr]=e[ed].data;
            }
        }
    }
    int main(){
        n=read(), m=read();
        for (int i=1; i<=m; i++){
            int u=read()+1, v=read()+1, w=read();
            build(u,v,w);
        }
        tuopu();
        bool flag=false; g[1]=1;
        for (int i=1; i<=n; i++){
            if (flag==false&&p[i]!=1) 
                continue;
            flag=true;
            int x=p[i]; double sum=0;
            for (int ed=head[x]; ed!=0; ed=e[ed].next)
                sum=sum+e[ed].vote;
            for (int ed=head[x]; ed!=0; ed=e[ed].next)
                g[e[ed].data]=g[e[ed].data]+g[x]*e[ed].vote/sum;
        }
        for (int i=n; i>=1; i--){
            int x=p[i];
            sum[x]=0,cnt[x]=0,num[x]=0;
            for (int ed=head[x]; ed!=0; ed=e[ed].next){
                sum[x]=sum[x]+e[ed].vote;
                cnt[x]=cnt[x]+e[ed].vote*f[e[ed].data];
                num[x]++;
            }
            if (sum[x]!=0) f[x]=cnt[x]/sum[x]+1;
        }
        tot=ans=f[1];
        for (int i=n; i>=1; i--){
            int x=p[i];
            if (num[x]<=1) continue;
            double now=tot-g[x]*f[x];
            for (int ed=head[x]; ed!=0; ed=e[ed].next){
                double nowsum=sum[x]-e[ed].vote,
                    nowcnt=cnt[x]-e[ed].vote*f[e[ed].data];
                ans=max(ans,now+g[x]*(nowcnt/nowsum+1));
            }
        }
        printf("%.6lf
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    最小生成树模板
    字符串模板
    单调队列
    代码优化
    ZJUT11 多校赛补题记录
    树链剖分
    网络基础及网络设备
    交换机介绍及选购全攻略
    将函数的返回值引用定义为引用
    函数指针和指针函数
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9135958.html
Copyright © 2020-2023  润新知