题意:给出一个DAG,一只机器人从1点出发,等概率地选择一条出边走或者停留在原点,机器人的第k次行动消耗能量是k(无论是走还是停留都算一次行动)。问1到n的期望。
解法:因为行动消耗的能量跟行动次数有关(有点像求E(x^2)的味道),考虑做两次概率DP。
dp1[x]表示点x到终点n的期望天数,那么dp1[x]=( dp1[x]+sigma(dp1[y]) ) / (du+1) + 1 。(du是x点度数,y是x儿子)。
dp2[x]表示点x到终点n的期望代价,那么dp2[x]=( dp2[x]+dp1[x]+1 + sigma(dp2[y]+dp1[y]+1) ) / (du+1)。(du和y同上)
先求dp1之后求dp2,答案就是dp2[1]。
代码写得很丑:
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; int n,m; vector<int> G[N]; double dp1[N],dp2[N]; void dfs1(int x) { if (x==n) return; if (dp1[x]!=0) return; double tmp=0; for (int i=0;i<G[x].size();i++) { int y=G[x][i]; dfs1(y); tmp+=dp1[y]; } tmp+=G[x].size()+1; tmp/=(double)G[x].size(); dp1[x]=tmp; } void dfs2(int x) { if (x==n) return; if (dp2[x]!=0) return; double tmp=0; for (int i=0;i<G[x].size();i++) { int y=G[x][i]; dfs2(y); tmp+=dp2[y]+dp1[y]+1; } tmp+=dp1[x]+1; tmp/=(double)G[x].size(); dp2[x]=tmp; } int main() { int T; cin>>T; while (T--) { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) G[i].clear(); for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); G[x].push_back(y); } for (int i=1;i<=n;i++) dp1[i]=dp2[i]=0; dfs1(1); dfs2(1); printf("%.2lf ",dp2[1]); } return 0; }