校内模拟赛 虫洞(by NiroBC)

题意:

  n个点m条边的有向图,每一天每条边存在的概率都是p,在最优策略下,询问从1到n的期望天数。

分析:

  dijkstra。

  每次一定会优先选dp最小的后继走,如果这条边不存在,选次小的,以此类推。

  dp[i]表示从i开始到n的期望天数,从后往前推,每次取出dp最小的,更新其他点。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cctype>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#define pa pair<double,int>
#define fore(i, u, v) for (int i = head[u], v = e[i].to; i; i = e[i].nxt, v = e[i].to) 
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 200005;
struct Edge { int to, nxt; double w; } e[N << 1];
int head[N], En, n, m;
double P[N], dp[N], sp[N], s[N], tp[N];
bool vis[N];

inline void add_edge(int u,int v,int w) {
    ++En; e[En].to = v, e[En].w = 1.0 * w / 100.0, e[En].nxt = head[u]; head[u] = En;
}
void Dijkstra() {
    priority_queue< pa, vector< pa >, greater< pa > > q;
    for (int i = 1; i <= n; ++i) dp[i] = 1e18, tp[i] = 1.0;
    q.push(pa(0, n)); dp[n] = 0; 
    while (!q.empty()) {
        int u = q.top().second; q.pop();
        if (vis[u]) continue; vis[u] = 1;
        fore(i, u, v) {
            double sum = s[v] + dp[u] * e[i].w * tp[v];
            double sump = sp[v] + e[i].w * tp[v];
            if (dp[v] > (sum + 1.0) / sump) {
                dp[v] = (sum + 1.0) / sump;
                s[v] += dp[u] * e[i].w * tp[v];
                sp[v] += e[i].w * tp[v];
                tp[v] *= (1 - e[i].w);
                q.push(pa(dp[v], v));
            }
        }
    }
    printf("%.3lf\n", dp[1]);
}
int main() {
    n = read(), m = read();
    for (int u, v, w, i = 1; i <= m; ++i) 
        u = read(), v = read(), w = read(), add_edge(v, u, w);
    Dijkstra();
    return 0;
}

 

posted @ 2019-04-02 20:26  MJT12044  阅读(373)  评论(0编辑  收藏  举报