[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\n",ans);
    return 0;
}
posted @ 2018-04-14 20:25  Vanisher  阅读(94)  评论(0编辑  收藏  举报