2019 ICPC 南京网络赛D - Robots

link:https://nanti.jisuanke.com/t/41301
思路link:https://blog.csdn.net/weixin_43394931/article/details/100513821

题意

给出一个n个点的DAG,起点保证为1,终点保证为n,在每一个点,每一天有等概率走向其相邻的点或是停在原点。在第i天的损耗值为i,求走到终点的期望损耗值。

思路

定义两个数组 d [ i ] , c [ i ] d[i],c[i] d[i],c[i]分别代表第i个位置到终点的期望天数以及期望损耗值。
可以这么理解:第一天的损耗值为1,第二天为2,……,第x天为x。可以等价为第一天为x,第二天为x-1,……,第x天为1。
这样第 i i i个位置的期望损耗值可以由其指向的点 j j j更新而得,期望损耗值为 c [ j ] + d [ j ] + 1 c[j]+d[j]+1 c[j]+d[j]+1
可以列出方程:
d [ i ] = ∑ d [ j ] x + 1 + d [ i ] x + 1 + 1 d[i] = \frac{\sum{d[j]}}{x+1}+\frac{d[i]}{x+1}+1 d[i]=x+1d[j]+x+1d[i]+1 c [ i ] = ∑ c [ j ] + d [ j ] + 1 x + 1 + c [ i ] + d [ i ] + 1 x + 1 c[i] =\frac{\sum{c[j]+d[j]+1}}{x+1}+\frac{c[i]+d[i]+1}{x+1} c[i]=x+1c[j]+d[j]+1+x+1c[i]+d[i]+1
解得:
d [ i ] = ∑ d [ j ] x + x + 1 x d[i] = \frac{\sum{d[j]}}{x}+\frac{x+1}{x} d[i]=xd[j]+xx+1
c [ i ] = ∑ c [ j ] + d [ j ] + 1 x + d [ i ] + 1 x c[i] = \frac{\sum{c[j]+d[j]+1}}{x}+\frac{d[i]+1}{x} c[i]=xc[j]+d[j]+1+xd[i]+1
期望由于要逆推,所以需要先搞出拓扑序,然后从拓扑序反向更新。

代码
//
// Created by yjq on 2019/9/4.
//

#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define ld long double
#define ull unsigned long long
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)

const int maxn = 5e5 + 10;

struct pxy {
    int to, next;
} e[maxn * 2];
int head[maxn], cnt, id[maxn], od[maxn];

void ins(int x, int y) {
    e[++cnt].to = y;
    e[cnt].next = head[x];
    head[x] = cnt;
}

int n, m;
ld d[maxn], c[maxn];
queue<int> q;
vector<int> v;

int main() {
    __;
    int _;
    cin >> _;
    while (_--) {
        cin >> n >> m;
        memset(head, 0, sizeof head);
        memset(od, 0, sizeof od);
        memset(id, 0, sizeof id);
        for (int i = 1; i <= m; ++i) {
            int x, y;
            cin >> x >> y;
            od[x]++;
            id[y]++;
            ins(x, y);
        }
        v.clear();
        for (int i = 1; i <= n; ++i) {
            if (id[i] == 0)q.push(i);
        }
        while (!q.empty()) {
            int x = q.front();
            v.push_back(x);
            q.pop();
            for (int i = head[x]; i; i = e[i].next) {
                id[e[i].to]--;
                if (id[e[i].to] == 0)q.push(e[i].to);
            }
        }
        memset(d, 0, sizeof d);
        memset(c, 0, sizeof c);
        d[n] = 0;
        c[n] = 0;
        for (int i = (int) v.size() - 2; i >= 0; --i) {
            ld w = 0;
            int x = v[i];
            for (int j = head[x]; j; j = e[j].next) {
                w += d[e[j].to];
            }
            d[x] = w / (ld) od[x] + (ld) (od[x] + 1) / (ld) od[x];
        }
        for (int i = (int) v.size() - 2; i >= 0; --i) {
            ld w = 0;
            int x = v[i];
            for (int j = head[x]; j; j = e[j].next) {
                w += d[e[j].to] + c[e[j].to] + 1.0;
            }
            c[x] = w / (ld) od[x] + (d[x] + 1.0) / (ld) od[x];
        }
        cout << fixed << setprecision(2) << c[1] << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值