[JZOJ5522] 图

Posted guessycb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JZOJ5522] 图相关的知识,希望对你有一定的参考价值。

题目大意:

一个有向图,图中有\(n\)个点\(m\)条边且无重边无自环,
每秒第\(i\)条边出现的概率是\(\frac{p[i]}{100}\)
一开始\(Samjia\)\(1\)点,每一秒假设\(Samjia\)在点\(x\)上,
那么\(Samjia\)要从存在的边中选一条来走,不可以不走,
如果不存在可以走的边,那么\(Samjia\)就会\(gg\)(挂了),
假设\(Samjia\)绝顶聪明,问最后\(Samjia\)可以成功到达\(n\)的概率是多少。
.
输出只有一个实数表示答案,即最后\(Samjia\)可以成功到达n的概率,
你的答案与标准输出相差不超过\(1e-6\)即视为正确。
.
对于\(100\%\)的数据,\(2\leq n \leq 50,0\leq m\leq n*(n-1),0\leq p[i]\leq 100\)

思路及解法:

显然准确值求不出来(难不成你还搞微积分?) , 网上的正解都是 高斯消元调整法 啦 ,
然而这题其实可以不用这么高级的东西就可以水过去的(滑稽)。
首先假设我们也足够聪明,我们可以知道每个节点\(u\)的后继到达\(n\)的概率\(P_u\)
那么一个非常显然的贪心就是我们先会去走成功概率大的点。
如果成功概率最大的点对应的那条边没有出现,我们则走成功概率次大的边。
其实转移已经出来了。
现在我们的问题是:我们不够聪明,不知道后续节点的成功概率。
然后正解的方法就是随便试一个排列,然后高斯消元(虽然我并不知道怎么搞)。
其实直接倒着转移不就行了吗?
没错,就是这样。

具体实现:

我们设\(f[t][u]\)表示从\(u\)点出发,用不超过\(t\)秒的事件成功到达\(n\)点的最大概率。
那么每次转移的时候,我们先把\(f[t+1]\)从大到小排一遍序(这不就是高斯消元要求的东西吗?)
然后考虑转移:非常显然:
\[f[t][u] = f[t+1][v]*happen*pb[u][v]\]
其中\(pb[u][v]\)\(*(u->v)\)这条边存在的概率,\(happen\)则是时间发生的概率。
那么关键是事件发生的概率\(happen\)怎么求。
由我们之前确定的贪心策略可以知道:
走向一个点发生的概率为 连接 成功概率比它大的点 的边 都不存在的概率
所以
\[happen_v = \prod_{r=1}^{n} (100\%-pb[u][v])*[\ f[t+1][r]>f[t+1][v]\ ]\]
一边 \(DP\) 一边处理即可。
至于精度要求的问题,跑个一两万次精度就符合要求了。

实现代码:

#include<bits/stdc++.h>
#define RG register
#define IL inline
using namespace std;

double pb[70][70];  int n,m;
struct F{double p; int id;}f[20005][70];
IL bool cmp(F a,F b){return a.p>b.p;}

int main(){
    cin >> n >> m;
    for(RG int i = 1; i <= m; i ++){
        RG double ppp; RG int xxx,yyy;
        cin >> xxx >> yyy >> ppp;
        pb[xxx][yyy] = 1.0*ppp/100;
    }
    for(RG int i = 1; i <= n; i ++)f[15000][i] = (F){0,i};
    f[15000][n] = (F){1,n};
    for(RG int i = 14999; i >= 1; i --){
        f[i+1][n] = (F){1,n};
        sort(f[i+1]+1,f[i+1]+n+1,cmp);
        for(RG int v = 1; v <= n-1; v ++){
            f[i][v] = (F){0,v};
            RG double happen = 1;
            for(RG int j = 1; j <= n; j ++){
                RG int u = f[i+1][j].id;
                f[i][v].p += f[i+1][j].p*happen*pb[v][u];
                happen = happen*(1 - pb[v][u]);
            }
        }
    }
    printf("%.10lf",f[1][1].p);  return 0;
}

以上是关于[JZOJ5522] 图的主要内容,如果未能解决你的问题,请参考以下文章

JZOJ5433图

JZOJ19142011集训队出题最短路

JZOJ573820190706锁屏杀

[最小生成树][并查集]JZOJ 2940 生成输入数据

如何将 r ggplot 图存储为 html 代码片段

[SPFA]JZOJ 3086 回家