捡石头——(期望递推)

描述
XXX发现他生活的村有很多值钱的石头。XXX 所在的村有 N 堆石头,第 i 堆的价值为 Vi。另有 M 条单向道路连接这些石头堆,满足从任意一堆石头出发沿着这些道路不会回到 起点。XXX 打算来一次捡石头之旅。由于他没有地图,他无法知道应该怎么走。因此他 只能采取这样的策略:每次从当前所在石头堆等概率随机选择一条可走的道路,走过去。 XXX 到达一堆石头后就会立刻把它们捡进自己的包里面。初始时,XXX 将等概率随机 空降到一个石头堆。现在,xxx向请你帮他算出他期望能得到多少价值的石头。
输入
第一行两个整数 N, M ,分别为石头堆数和单向道路数。 接下来一行 N 个正整数表示 Vi。 接下来 M 行,每行两个整数 a b,表示一条从 a 到 b 的单向道路。
输出
输出一行一个实数表示答案。四舍五入保留两位小数即可。
样例输入
1 0
1
样例输出
1.00
提示
对于 50%的数据, N, M<=100 。 对于 100%的数据,1<= N, M <=10^5,1<=V i<=10^4

由于是个DAG

所以直接建反向边,拓扑排序,直接向父亲传递信息就是了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
    char ch=getchar();
    int res=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res*f;
}
const int N=100005;
int adj[N],nxt[N],to[N],a[N],n,m,in[N],cnt,siz[N];
inline void addedge(int u,int v){
    nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
double ans,hop[N];
queue<int> q;
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        addedge(v,u),in[u]++;
    }
    for(int i=1;i<=n;i++){
        if(in[i]==0)q.push(i);
    }
    while(!q.empty()){
        int u=q.front();q.pop();
        if(siz[u])hop[u]/=(double)(siz[u]);
        hop[u]+=a[u];
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            siz[v]++,hop[v]+=hop[u],in[v]--;
            if(in[v]==0)q.push(v);
        }
    }
    for(int i=1;i<=n;i++){
        ans+=hop[i];
    }
    ans=ans/((double)(n*1.0));
    printf("%.2lf",ans);
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366400.html