分析:
其实这道题是可以正着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;
}