题意:
给定n个顶点m条边的有向无环图
一个机器人从1出发,有等概率走任意一条出边或者原地不动,每次移动需要能量,能量大小等于当前经过的天数,求从1到n的能量消耗期望
数据范围:n,m<=2e5
思路:
day[i]表示i到n的天数期望
out[i]表示i的出度
则day的转移方程为day[x]=1/(out[x]+1)∗∑day[v]+1/(out[x]+1)∗day[v]+1
其中:
1/(out[x]+1)∗∑day[v]是走的
1/(out[x]+1)∗day[x]是不走的
1是天数(移动需要一天)
cost[x]=1/(out[x]+1)∗∑cost[v]+1/(out[x]+1)∗cost[x]+day[x]
其中:
1/(out[x]+1)∗∑cost[v]是走的
1/(out[x]+1)∗cost[x]是不走的
day[x]是天数(移动消耗的能量)
化简一下:
day[x]移项化简得day[x]=(∑day[v]+len+1)/out[x]
cost[x]同理
dfs记忆化搜索
从后往前推
code:
//https://nanti.jisuanke.com/t/41301
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxm=1e5+5;
vector<int>g[maxm];
int mark[maxm];
int n,m;
double day[maxm];
double cost[maxm];
void init(){
for(int i=1;i<=n;i++){
g[i].clear();
}
memset(mark,0,sizeof mark);
}
void dfs(int x){
if(mark[x])return ;
mark[x]=1;//标记搜过的点,否则多入度点会被重复搜索
day[x]=0;
cost[x]=0;
if(x==n)return ;
int len=g[x].size();//len同时也是出度
for(int i=0;i<len;i++){
int v=g[x][i];
dfs(v);
day[x]+=day[v];
cost[x]+=cost[v];
}
day[x]=(day[x]+len+1)/len;
cost[x]=(cost[x]+(len+1)*day[x])/len;
}
signed main(){
int T;
scanf("%d",&T);
while(T--){
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
g[a].push_back(b);
}
dfs(1);
printf("%.2f\n",cost[1]);
}
return 0;
}