题面传送门

之所以写个题解是因为题解区大部分题解的做法都有 bug(u1s1 周六上午在讨论区里连发两个 hack 的是我,由于我被禁言才让 ycx 代发的)

首先碰到这种期望题,我们套路地设 \(dp_u\) 为从节点 \(u\) 走到节点 \(n\) 经过的节点数的期望值,那么显然有转移方程 \(dp_u=\dfrac{1}{deg_u}(\sum\limits_{(u,v)\in E}dp_v)+1\),由于这个 \(dp\) 方程存在环,故需按照 P3232 游走 的套路进行高斯消元,具体来说你将这 \(n\) 个 \(dp\) 转移式写成矩阵的形式高斯消元一下即可。

等等……\(10^4\) 你让我跑高斯消元?

注意到题目中有个条件,就是每个强连通分量大小 \(\le 100\),因此考虑先将原图进行一遍 SCC 缩点,缩点完成后显然原图变成了一个 DAG,我们考虑按这个 DAG 的拓扑序倒序(或者说,以 \(t\) 为起点拓扑排序)对每个强连通分量中的点计算一遍 \(dp\) 值,具体来说我们给当前强连通分量中的所有点重新编号,对于形如 \(dp_u=\dfrac{1}{deg_u}(\sum\limits_{(u,v)\in E}dp_v)+1\) 的式子,如果 \(v\) 与 \(u\) 在同一个强连通分量中那就按照套路将式子改写成一个 \(dp_u\) 与这样的 \(dp_v\) 的关系式,否则由于我们按照拓扑序倒序计算答案,\(dp_v\) 的值肯定已经计算好了,那么我们把它当作常数项拖到右边去即可。具体实现的时候可以以 \(s\) 为起点跑一遍 tarjan,因为最终强连通分量的编号本身就是按拓扑序倒序编好号的了,就 duck 不必再写遍拓扑排序了,直接从 \(1\) 枚举到 \(\text{强连通分量个数}\) 依次计算即可。

记 \(s_i\) 为强连通分量大小,那么该算法复杂度 \(T(n)=\sum\limits_{i=1}^ms_i^3\),而 \(s_i\le 100\),故 \(T(n)\le\dfrac{10^4}{100}\times 100^3=10^8\),可以通过此题。

那么什么情况输出 INF 呢?显然如果 \(s\) 不能到 \(t\) 答案肯定是 INF,接下来就是我要强调的地方了,不少题解都认为,只要存在 \(s\) 能到达但却不能到达 \(t\) 的点就 INF,但考虑下面的数据:

3 2 1 3
1 3
3 2

事实上,\(2\) 虽然能够从 \(3\) 到达,但从 \(1\to 2\) 的路径上已经经过 \(3\) 了,因此是可以到达 \(2\) 的,答案应当为 \(1.000\)。

还有的题解稍微明智些,把不能到达的点的 \(dp\) 值设为 \(\infty\),然后判是否有 \(dp_s=\infty\),这样做是可以避免掉上述情况的,但由于实现上出了个小 bug(如果一个点出度为 \(0\) 那么它的 \(dp\) 值就是 \(\infty\)),导致其可以被以下的数据叉掉:

5 5 1 5
1 5
1 2
2 3
3 4
4 2

我的做法是,先建反图,以 \(t\) 为起点做一遍 DFS 找出所有能到达 \(t\) 的点,然后如果一个点不能到达 \(t\) 那就令它的 \(dp\) 值为 \(\infty\),这样又可避免上述情况。

当然我的做法可能也存在漏洞(只是我发现不了了),如果发现漏洞请及时提出,谢谢。

我认为做题还是要严谨些,愿管理员把 hack 数据加入本题的测试数据中。

那问题就来了,为什么我就不能把我 hack 的这份热情放到 CF 比赛中呢

const int MAXS=100;
const int MAXN=10000;
const int MAXM=1e6;
const double INF=1e15;
int n,m,s,t;
int hd[MAXN+5],to[MAXM*2+5],nxt[MAXM*2+5],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int bel[MAXN+5],cmp=0,dfn[MAXN+5],low[MAXN+5],tim=0;
bool vis[MAXN+5];int stk[MAXN+5],top=0;vector<int> scc[MAXN+5];
vector<int> rev[MAXN+5];bool can[MAXN+5];
void dfs(int x){
if(can[x]) return;can[x]=1;
for(int y:rev[x]) dfs(y);
}
void tarjan(int x){
dfn[x]=low[x]=++tim;vis[x]=1;stk[++top]=x;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];
if(!dfn[y]) tarjan(y),chkmin(low[x],low[y]);
else if(vis[y]) chkmin(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
cmp++;int o;
do {
o=stk[top--];vis[o]=0;
scc[bel[o]=cmp].pb(o);
} while(o!=x);
}
}
int id[MAXN+5],seq[MAXS+5],subsiz=0,deg[MAXN+5];
double dp[MAXN+5],a[MAXS+5][MAXS+5],f[MAXS+5];
int main(){
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);deg[u]++;
adde(u,v);rev[v].pb(u);
}
tarjan(s);dfs(t);if(!dfn[t]) return puts("INF"),0;
for(int i=1;i<=cmp;i++){
subsiz=0;memset(a,0,sizeof(a));memset(f,0,sizeof(f));
for(int u:scc[i]){seq[++subsiz]=u;id[u]=subsiz;}
for(int u:scc[i]){
int p=id[u];
if(u==t){a[p][p]=1;continue;}
a[p][p]=a[p][subsiz+1]=deg[u];
for(int e=hd[u];e;e=nxt[e]){
int v=to[e];
if(bel[v]==bel[u]) a[p][id[v]]--;
else a[p][subsiz+1]+=dp[v];
}
if(!can[u]) a[p][subsiz+1]=INF;
}
// for(int j=1;j<=subsiz;j++) for(int k=1;k<=subsiz+1;k++)
// printf("%.3lf%c",a[j][k],(k==subsiz+1)?'\n':' ');
for(int j=1;j<=subsiz;j++){
int t=j;
for(int k=j+1;k<=subsiz;k++) if(fabs(a[k][j])>fabs(a[t][j])) t=k;
for(int k=j;k<=subsiz+1;k++) swap(a[t][k],a[j][k]);
for(int k=j+1;k<=subsiz+1;k++) a[j][k]/=a[j][j];a[j][j]=1;
for(int k=j+1;k<=subsiz;k++){
for(int l=j+1;l<=subsiz+1;l++) a[k][l]-=a[k][j]*a[j][l];
a[k][j]=0;
}
}
for(int j=subsiz;j;j--){
f[j]=a[j][subsiz+1];
for(int k=j+1;k<=subsiz;k++) f[j]-=f[k]*a[j][k];
// printf("%.3lf\n",f[j]);
}
for(int j=1;j<=subsiz;j++){
if(f[j]>1e9) dp[seq[j]]=INF;
else dp[seq[j]]=f[j];
}
}
// for(int i=1;i<=n;i++) cout<<dp[i]<<endl;
if(dp[s]>1e9) puts("INF");
else printf("%.3lf\n",dp[s]);
return 0;
}

洛谷 P6030 - [SDOI2012]走迷宫(高斯消元+SCC 缩点)的更多相关文章

  1. BZOJ 2707: [SDOI2012]走迷宫 [高斯消元 scc缩点]

    2707: [SDOI2012]走迷宫 题意:求s走到t期望步数,\(n \le 10^4\),保证\(|SCC| \le 100\) 求scc缩点,每个scc高斯消元,scc之间直接DP 注意每次清 ...

  2. l洛谷 P6030 [SDOI2012]走迷宫 概率与期望+高斯消元

    题目描述 传送门 分析 首先判掉 \(INF\) 的情况 第一种情况就是不能从 \(s\) 走到 \(t\) 第二种情况就是从 \(s\) 出发走到了出度为 \(0\) 的点,这样就再也走不到 \(t ...

  3. 洛谷P2973 [USACO10HOL]赶小猪(高斯消元 期望)

    题意 题目链接 Sol 设\(f[i]\)表示炸弹到达\(i\)这个点的概率,转移的时候考虑从哪个点转移而来 \(f[i] = \sum_{\frac{f(j) * (1 - \frac{p}{q}) ...

  4. 洛谷3317 SDOI2014重建(高斯消元+期望)

    qwq 一开始想了个错的做法. 哎 直接开始说比较正确的做法吧. 首先我们考虑题目的\(ans\)该怎么去求 我们令\(x\)表示原图中的某一条边 \[ans = \sum \prod_{x\in t ...

  5. 【BZOJ3143】游走(高斯消元,数学期望)

    [BZOJ3143]游走(高斯消元,数学期望) 题面 BZOJ 题解 首先,概率不会直接算... 所以来一个逼近法算概率 这样就可以求出每一条边的概率 随着走的步数的增多,答案越接近 (我卡到\(50 ...

  6. 洛谷P3232 [HNOI2013]游走(高斯消元+期望)

    传送门 所以说我讨厌数学……期望不会高斯消元也不会……好不容易抄好了高斯消元板子被精度卡成琪露诺了…… 首先,我们先算出走每一条边的期望次数,那么为了最小化期望,就让大的期望次数乘上小编号 边的期望次 ...

  7. [HNOI2013]游走 期望+高斯消元

    纪念首道期望题(虽说绿豆蛙的归宿才是,但是我打的深搜总觉得不正规). 我们求出每条边的期望经过次数,然后排序,经过多的序号小,经过少的序号大,这样就可以保证最后的值最小. 对于每一条边的期望经过次数, ...

  8. LOJ 2542 「PKUWC2018」随机游走 ——树上高斯消元(期望DP)+最值反演+fmt

    题目:https://loj.ac/problem/2542 可以最值反演.注意 min 不是独立地算从根走到每个点的最小值,在点集里取 min ,而是整体来看,“从根开始走到点集中的任意一个点就停下 ...

  9. 【BZOJ】3143: [Hnoi2013]游走 期望+高斯消元

    [题意]给定n个点m条边的无向连通图,每条路径的代价是其编号大小,每个点等概率往周围走,要求给所有边编号,使得从1到n的期望总分最小(求该总分).n<=500. [算法]期望+高斯消元 [题解] ...

随机推荐

  1. java---String 和 StringBuffer

    Java-String和StringBuffer类 Java String 类 字符串在Java中属于对象,Java提供String类来创建和操作字符串. 创建字符串 创建字符串常用的方法如下: ​ ...

  2. vue2和vue3比较

    一.vue3新特性: 1.数据响应重新实现(ES6的proxy代替Es5的Object.defineProperty) 2.源码使用ts重写,更好的类型推导 3.虚拟DOM新算法(更快,更小) 4.提 ...

  3. [LGP2758]编辑距离

    目录 题目 题目描述 输入格式 输出格式 输入输出样例 题目分析 状态转移方程 初始状态 结束状态 Code 题目 题目描述 设A和B是两个字符串.我们要用最少的字符操作次数,将字符串A转换为字符串B ...

  4. 2021 ICPC Gran Premio de Mexico 2da Fecha部分题题解

    前面的水题,在队友的配合下,很快就拿下了,剩下几道大毒瘤题,一直罚座三个小时,好让人自闭...但不得不说,这些题的质量是真的高! H. Haunted House 首先看这个题,大眼一扫,觉得是某种数 ...

  5. 如何反编译微信小程序👻

    如何反编译微信小程序 准备工具: 夜神模拟器(或者你可以自己准备一个安卓模拟器,有root权限.) RE文件管理器(下载地址:https://soft.ucbug.com/uploads/shouji ...

  6. Go语言核心36讲(Go语言进阶技术十二)--学习笔记

    18 | if语句.for语句和switch语句 现在,让我们暂时走下神坛,回归民间.我今天要讲的if语句.for语句和switch语句都属于 Go 语言的基本流程控制语句.它们的语法看起来很朴素,但 ...

  7. python3 调用 centos 常用系统命令

    一.创建目录 1 import os 2 3 base_path = '/data/sw_backup' 4 addr= 'FT' 5 ip='192.168.1.1' 6 path = base_p ...

  8. ELK集群之grafana(8)

    Grafana的安装和读取ES数据 模拟es数据产生sjgtest.py import time import datetime from elasticsearch import Elasticse ...

  9. 攻防世界 WEB 高手进阶区 easytornado Writeup

    攻防世界 WEB 高手进阶区 easytornado Writeup 题目介绍 题目考点 Python模板 tornado 模板注入 Writeup 进入题目, 目录遍历得到 /flag.txt /w ...

  10. 【死磕 NIO】— Proactor模式是什么?很牛逼吗?

    大家好,我是大明哥. 上篇文章我们分析了高性能 IO模型Reactor模式,了解了什么是Reactor 模式以及它的三种常见的模式,这篇文章,大明再介绍另外一种高性能IO模型: Proactor. 为 ...