19 南京icpc网络赛 Robots //有向无环图上概率dp

题意:给一个有向无环图,且0无入边,1无出边,有一个机器人,从1号点走到n点,每次有等概率原地不动或者向任意一条出边走,每次走的花费是已经过了的天数。求走到n时的期望花费。

思路:

先求期望时间,再求期望花费。

定义t[i]为i到n所需要的时间,定义dp[i]为i到n所需要的花费,j为i的出边的终点。

\large t[i]=\sum \frac{t[j]}{out[i]+1}+\frac{t[i]}{out[i]+1}+1

\large t[i]=\sum \frac{t[j]}{out[i]}+\frac{out[i]+1}{out[i]}

\large dp[i]=\sum \frac{dp[j]}{out[i]+1}+\frac{dp[i]}{out[i]+1}+t[i]

\large dp[i]=\sum \frac{dp[j]}{out[i]}+t[i]*\frac{out[i]+1}{out[i]}

逆向拓扑。

这样做似乎是合理的....因为每次t和dp都是平均值然后相加,将ti倒过来相加似乎也没什么问题。(不会证明

/*   Author : Rshs
 *   Data : 2019-09-03
 */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const LL mod = 1e9+7;
const int MX = 1e5+5;
int chu[MX];
vector<int>g[MX],rg[MX];
double t[MX],dp[MX];
void Main(int avg){
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) rg[i].clear(),g[i].clear(),chu[i]=0;
    for(int i=1;i<=m;i++){
        int IA,IB;scanf("%d%d",&IA,&IB);
        g[IA].push_back(IB);
        rg[IB].push_back(IA);
        chu[IA]++;
    }
    queue<int>q;q.push(n);t[n]=0,dp[n]=0;
    while(!q.empty()){
        int now=q.front();q.pop();
        double szout=(double)g[now].size();
        for(auto i:rg[now]){
            chu[i]--;if(chu[i]==0)q.push(i);
        }
        if(now==n)continue;
        t[now]=(szout+1)/szout;
        for(auto i:g[now]){
            t[now]+=t[i]/szout;
        }
        dp[now]=t[now]*(szout+1)/szout;
        for(auto i:g[now]){
            dp[now]+=dp[i]/szout;
        }
    }
    printf("%.2lf\n",dp[1]);
}
int main(){
    int cas;cin>>cas;for(int i=1;i<=cas;i++)Main(i);
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值