【BZOJ】3036: 绿豆蛙的归宿

【题意】给定DAG带边权连通图,保证所有点都能到达终点n,每个点等概率沿边走,求起点1到终点n的期望长度。n<=10^5。

【算法】期望DP

【题解】f[i]表示到终点n的期望长度。

f[n]=0

f[i]=(f[j]+e[i].w)/k[i],i-->j,k[i]是i的出度。

因为是点x等概率出发,所以一定要从x算,不能倒着来。

原理:【专题】概率和期望

考虑到深搜的爆栈风险,写了拓扑排序+期望DP

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=200010;
int first[maxn],n,m,in[maxn],a[maxn],tot=0,k[maxn],cnt=0;//////////////////////
double f[maxn];
queue<int>q;
struct edge{int v,w,from;}e[maxn*2];
void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;in[v]++;k[u]++;}
int main(){
    scanf("%d%d",&n,&m);
    int u,v,w;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&u,&v,&w);
        insert(u,v,w);
    }
    for(int i=1;i<=n;i++)if(!in[i])q.push(i);
    while(!q.empty()){
        a[++cnt]=q.front();q.pop();
        for(int i=first[a[cnt]];i;i=e[i].from){
            in[e[i].v]--;
            if(!in[e[i].v])q.push(e[i].v);
        }
    }
    for(int j=n;j>=1;j--){
        int x=a[j];
        for(int i=first[x];i;i=e[i].from){
            f[x]+=f[e[i].v]+e[i].w;
        }
        if(k[x])f[x]/=k[x];
    }
    printf("%.2lf",f[1]);
    return 0;
}
View Code

有边表的tot时,一定要注意不要用变量tot。

posted @ 2017-10-18 10:52  ONION_CYC  阅读(493)  评论(0编辑  收藏  举报