2019南京网络赛 D. Robots(概率DP与拓扑排序)

题目链接
在做这道题之前看一个简化版:绿豆蛙的归宿
F [ x ] F[x] F[x] 表示从 x x x 走到终点所经过的路径的期望长度。若从 x x x 出发有 k k k 条边,分别到达 y 1 , y 2 . . . y k y_1,y_2...y_k y1,y2...yk ,边长分别为 z 1 , z 2 . . . z k z_1,z_2...z_k z1,z2...zk ,则根据数学期望的定义和性质,有: F [ x ] = 1 k ∗ ∑ i = 1 k ( F [ y i ] + z i ) F[x]=\frac{1}{k}*\sum_{i=1}^k(F[y_i]+z_i) F[x]=k1i=1k(F[yi]+zi)
就可以将边取反然后用拓扑排序解决。

现在这道题在上面这道题的基础上相当于将边长设置为 1 ,然后多了一个每次多走一条边的花费。
每个点到 n n n 点的距离相当于: F d a y [ i ] = 1 d e g [ i ] + 1 ∗ ∑ j = 1 d e g [ i ] ( F d a y [ i ] + 1 ) + 1 d e g [ i ] + 1 ∗ ( F d a y [ i ] + 1 ) F_{day}[i]=\frac{1}{deg[i]+1}*\sum_{j=1}^{deg[i]}(F_{day}[i]+1)+\frac{1}{deg[i]+1}*(F_{day}[i]+1) Fday[i]=deg[i]+11j=1deg[i](Fday[i]+1)+deg[i]+11(Fday[i]+1)化简之后: F d a y [ i ] = 1 d e g [ i ] ∗ ∑ j = 1 d e g [ i ] F d a y [ i ] + 1 d e g [ i ] + 1 F_{day}[i]=\frac{1}{deg[i]}*\sum_{j=1}^{deg[i]}F_{day}[i]+\frac{1}{deg[i]}+1 Fday[i]=deg[i]1j=1deg[i]Fday[i]+deg[i]1+1
每个点到 n n n 点的花费相当于: F c o s t [ i ] = 1 d e g [ i ] + 1 ∗ ∑ j = 1 d e g [ i ] ( F c o s t [ i ] + F d a y [ i ] ) + 1 d e g [ i ] + 1 ∗ ( F c o s t [ i ] + F d a y [ i ] ) F_{cost}[i]=\frac{1}{deg[i]+1}*\sum_{j=1}^{deg[i]}(F_{cost}[i]+F_{day}[i])+\frac{1}{deg[i]+1}*(F_{cost}[i]+F_{day}[i]) Fcost[i]=deg[i]+11j=1deg[i](Fcost[i]+Fday[i])+deg[i]+11(Fcost[i]+Fday[i])化简后: F c o s t [ i ] = 1 d e g [ i ] ∗ ∑ j = 1 d e g [ i ] F c o s t [ i ] + F d a y [ i ] d e g [ i ] + F d a y [ i ] F_{cost}[i]=\frac{1}{deg[i]}*\sum_{j=1}^{deg[i]}F_{cost}[i]+\frac{F_{day}[i]}{deg[i]}+F_{day}[i] Fcost[i]=deg[i]1j=1deg[i]Fcost[i]+deg[i]Fday[i]+Fday[i]
由于我太菜,拓扑排序的版本我写的一直不对,改成 dfs 的写法之后就对了,要记得记忆化,不然会超时。

简化版代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<double, int>
#define debug(x) cout << (#x) << ": " << (x) << " "
#define fastio ios::sync_with_stdio(false), cin.tie(0)
const int mod = 1e9 + 7;
const int M = 1000000 + 10;
const int N = 1000000 + 10;

int n, m, a, b;
double c;
vector<P> G[N];
int du[N], deg[N];
double f[N];

signed main()
{
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= m; i ++) {
        scanf("%d %d %lf", &a, &b, &c);
        G[b].push_back(P{c, a});
        du[a] ++, deg[a] ++;
    }

    queue<int> que;
    que.push(n);
    while(que.size()) {
        int now = que.front();
        que.pop();
        for(int i = 0; i < G[now].size(); i ++) {
            f[G[now][i].second] += (f[now] + G[now][i].first) / deg[G[now][i].second];
            du[G[now][i].second] --;
            if(!du[G[now][i].second]) que.push(G[now][i].second);
        }
    }
    printf("%.2lf\n", f[1]);

    return 0;
}

/*

  Rejoicing in hope, patient in tribulation .

*/

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<int, int>
#define debug(x) cout << (#x) << ": " << (x) << " "
#define fastio ios::sync_with_stdio(false), cin.tie(0)
const int mod = 1e9 + 7;
const int M = 1000000 + 10;
const int N = 400000 + 10;

int t, n, m, a, b;
double f_day[N], f_cost[N];
int deg[N];
vector<int> G[N];

void init()
{
    for(int i = 1; i <= n; ++ i) {
        f_day[i] = f_cost[i] = deg[i] = 0;
        G[i].clear();
    }
}

double dfs_day(int now)
{
    if(now == n) return 0;
    if(f_day[now]) return f_day[now];
    double sum = 0;
    for(int i = 0; i < G[now].size(); ++ i) {
        sum += dfs_day(G[now][i]);
    }
    return f_day[now] = sum / deg[now] + 1 + 1.0 / deg[now];
}

double dfs_cost(int now)
{
    if(now == n) return 0;
    if(f_cost[now]) return f_cost[now];
    double sum = 0;
    for(int i = 0; i < G[now].size(); ++ i) {
        sum += dfs_cost(G[now][i]);
    }
    return f_cost[now] = sum / deg[now] + f_day[now] + f_day[now] / deg[now];
}

signed main()
{
    scanf("%d", &t);
    while(t --) {
        scanf("%d %d", &n, &m);
        init();
        for(int i = 1; i <= m; ++ i) {
            scanf("%d %d", &a, &b);
            G[a].push_back(b);
            deg[a] ++;
        }

        dfs_day(1);
        dfs_cost(1);

        printf("%.2f\n", f_cost[1]);
    }
    return 0;
}

/*

  Rejoicing in hope, patient in tribulation .

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值