[BZOJ3036]綠豆蛙的歸宿:DAG上DP+期望DP
阿新 • • 發佈:2018-11-11
分析:
其實這道題是可以正著DP的(即不需要在反圖上拓撲排序)(為什麼好多人都說不能?)
我們令f[i]表示從起點1出發到點i的期望距離,如果一些點能到達點i,那麼這些點中的每個點對f[i]的貢獻為f[j]*po[j],po[j]表示通過j到達i的概率。實際上,我們令p[i]表示從起點1出發能到達i的概率,這個p[i]可以在拓撲排序同時求出,那麼po[j]=(p[j]/out_deg[j])/p[i]。考慮到拓撲排序到j時我們還不知道p[i]的值,所以可以先給f[i]加上f[j]*(p[j]/out_deg[j]),在排到i時再給f[i]除以p[i]即可。
程式碼:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <cctype> #include <algorithm> #include <queue> typedef long long LL; inline int read(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x; } const int MAXN=100005; int n,m,ecnt,head[MAXN],in_deg[MAXN],out_deg[MAXN]; double p[MAXN],f[MAXN]; struct Edge{ int to,nxt; LL w; }e[MAXN<<1]; std::queue<int> q; inline void add_edge(int bg,int ed,LL val){ ecnt++; e[ecnt].to=ed; e[ecnt].nxt=head[bg]; e[ecnt].w=val; head[bg]=ecnt; } int main(){ n=read(),m=read(); for(int i=1;i<=m;i++){ int u=read(),v=read(); LL w=read(); add_edge(u,v,w); in_deg[v]++; out_deg[u]++; } while(!q.empty()) q.pop(); q.push(1); f[1]=0,p[1]=1.0; while(!q.empty()){ int x=q.front();q.pop(); f[x]/=p[x]; for(int i=head[x];i;i=e[i].nxt){ int ver=e[i].to; p[ver]+=p[x]/out_deg[x]; f[ver]+=(f[x]+e[i].w)*(p[x]/out_deg[x]); in_deg[ver]--; if(!in_deg[ver]) q.push(ver); } } printf("%.2lf\n",f[n]); return 0; }