题目

Morenan被困在了一个迷宫里。迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T。可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的有向边,到达另一个点。这样,Morenan走的步数可能很长,也可能是无限,更可能到不了终点。若到不了终点,则步数视为无穷大。但你必须想方设法求出Morenan所走步数的期望值。

输入格式

第1行4个整数,N,M,S,T

第[2, M+1]行每行两个整数o1, o2,表示有一条从o1到o2的边。

输出格式

一个浮点数,保留小数点3位,为步数的期望值。若期望值为无穷大,则输出"INF"。

输入样例

9 12 1 9

1 2

2 3

3 1

3 4

3 7

4 5

5 6

6 4

6 7

7 8

8 9

9 7

输出样例

9.500

提示

测试点

N M

[1, 6] <=10 <=100

[7, 12] <=200 <=10000

[13, 20] <=10000 <=1000000

保证强连通分量的大小不超过100

另外,均匀分布着40%的数据,图中没有环,也没有自环

题解

此题和游走那题有异曲同工之妙

我们设\(f[i]\)表示从\(i\)点出发到达终点的期望步数

就有\(f[i] = \frac{\sum (f[to] + 1)}{outde[i]}\)

假若这是一个DAG图,反向dp就可以了

但是如果是一般有向图,我们进行缩点,先计算后面的强联通分量

同一个强联通分量之间,其式子的to要么是之后已经计算好了的点,要么就是强联通分量内部的点,可以用高斯消元解出

判定时,只需要看S出发到达的所有点能否都到达T就可以了

写起来真要命

T出发的边没有任何意义,不要添加,否则可能会导致方程组无解

我丑陋杂乱的代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
#define eps 1e-8
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 10005,maxm = 1000005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne = 2;
int h2[maxn],ne2 = 2;
int h3[maxn],ne3 = 2;
int n,m,S,T;
int inde[maxn];
double de[maxn];
struct EDGE{int to,nxt;}ed[maxm],ed2[maxm],ed3[maxm];
inline void build(int u,int v){
if (u == T) return;
ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
de[u] += 1;
ed3[ne3] = (EDGE){u,h3[v]}; h3[v] = ne3++;
}
inline void add(int u,int v){
ed2[ne2] = (EDGE){v,h2[u]}; h2[u] = ne++;
}
int dfn[maxn],low[maxn],st[maxn],Scc[maxn],scci,top,cnt;
vector<int> scc[maxn];
void dfs(int u){
dfn[u] = low[u] = ++cnt;
st[++top] = u;
Redge(u){
if (!dfn[to = ed[k].to]){
dfs(to);
low[u] = min(low[u],low[to]);
}else if (!Scc[to]) low[u] = min(low[u],dfn[to]);
}
if (low[u] == dfn[u]){
scci++;
do{
Scc[st[top]] = scci;
scc[scci].push_back(st[top]);
}while (st[top--] != u);
}
}
void tarjan(){
for (int i = 1; i <= n; i++) if (!dfn[i]) dfs(i);
}
void rebuild(){
for (int i = 1; i <= n; i++){
int u = Scc[i];
Redge(u) if (Scc[to = ed[k].to] != u)
add(Scc[to],u);
}
}
int vis[maxn];
void dfs1(int u){
vis[u] = 1;
Redge(u) if (!vis[to = ed[k].to]) dfs1(to);
}
void dfs2(int u){
vis[u] += 2;
for (int k = h3[u],to; k; k = ed3[k].nxt)
if (vis[to = ed3[k].to] <= 1) dfs2(to);
}
bool check(){
dfs1(S);
dfs2(T);
for (int i = 1; i <= n; i++) if (vis[i] == 1) return false;
return true;
}
double f[maxn];
double A[205][205];
int id[maxn],c[maxn];
void gause(int u){
int cnt = scc[u].size();
for (int i = 1; i <= cnt; i++){
c[i] = scc[u][i - 1];
id[c[i]] = i;
}
for (int i = 1; i <= cnt + 1; i++)
for (int j = 1; j <= cnt + 1; j++)
if (i != j) A[i][j] = 0;
else A[i][j] = 1;
for (int i = 1; i <= cnt; i++){
Redge(c[i]){
to = ed[k].to;
if (Scc[to] != u) A[i][cnt + 1] += (f[to] + 1) / de[c[i]];
else A[i][id[to]] -= 1 / de[c[i]],A[i][cnt + 1] += 1 / de[c[i]];
}
}
for (int i = 1; i <= cnt; i++){
int j = i;
while (j <= cnt && fabs(A[j][i]) <= eps) j++;
if (j == cnt + 1){
puts("INF");
exit(0);
}
if (j != i) for (int k = 1; k <= cnt + 1; k++)
swap(A[i][k],A[j][k]);
for (int j = i + 1; j <= cnt; j++){
if (fabs(A[j][i]) > eps){
double t = A[j][i];
for (int k = i; k <= cnt + 1; k++)
A[j][k] = A[j][k] / t * A[i][i];
for (int k = i; k <= cnt + 1; k++)
A[j][k] -= A[i][k];
}
}
}
for (int i = cnt; i; i--){
for (int j = i + 1; j <= cnt; j++)
A[i][cnt + 1] -= A[i][j] * f[c[j]];
if (fabs(A[i][i]) <= eps){
puts("INF");
exit(0);
}
A[i][cnt + 1] /= A[i][i];
f[c[i]] = A[i][cnt + 1];
}
}
void solve(){
for (int i = 1; i <= scci; i++) gause(i);
printf("%.3lf\n",f[S]);
}
int main(){
n = read(); m = read(); S = read(); T = read();
int a,b;
while (m--){
a = read(); b = read();
build(a,b);
}
if (!check()){
puts("INF");
return 0;
}
tarjan();
rebuild();
solve();
return 0;
}

BZOJ2707 [SDOI2012]走迷宫 【概率dp + tarjan + 高斯消元】的更多相关文章

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

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

  2. 【BZOJ 2337】 2337: [HNOI2011]XOR和路径(概率DP、高斯消元)

    2337: [HNOI2011]XOR和路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1170  Solved: 683 Description ...

  3. hdu4418(概率dp + 高斯消元)

    应该是一个入门级别的题目. 但是有几个坑点. 1. 只选择x能到达的点作为guass中的未知数. 2. m可能大于n,所以在构建方程组时未知数的系数不能直接等于,要+= 3.题意貌似说的有问题,D为- ...

  4. BZOJ2707: [SDOI2012]走迷宫(期望 tarjan 高斯消元)

    题意 题目链接 Sol 设\(f[i]\)表示从\(i\)走到\(T\)的期望步数 显然有\(f[x] = \sum_{y} \frac{f[y]}{deg[x]} + 1\) 证明可以用全期望公式. ...

  5. BZOJ 2707: [SDOI2012]走迷宫( tarjan + 高斯消元 )

    数据范围太大不能直接高斯消元, tarjan缩点然后按拓扑逆序对每个强连通分量高斯消元就可以了. E(u) = 1 + Σ E(v) / degree(u) 对拍时发现网上2个程序的INF判断和我不一 ...

  6. BZOJ.2707.[SDOI2012]走迷宫(期望 Tarjan 高斯消元)

    题目链接 一个点到达终点的期望步数 \(E_i=\sum_{(i,j)\in G}\frac{E_j+1}{out[i]}\),\(out[i]\)为点\(i\)的出度. 那么对于一个DAG可以直接在 ...

  7. BZOJ2707 : [SDOI2012]走迷宫

    首先求出SCC缩点,E[T]=0,按拓扑序计算 对于无边连出的块,如果不是T所在块,则称该块是死路块 对于一个块,如果其中的点连出的边是死路块,则它也是死路块 否则对于每块进行高斯消元求出期望 如果S ...

  8. BZOJ 3143: [Hnoi2013]游走 概率与期望+高斯消元

    Description 一个无向连通图,顶点从1编号到N,边从1编号到M.小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获 ...

  9. loj2542 「PKUWC2018」随机游走 MinMax 容斥+树上高斯消元+状压 DP

    题目传送门 https://loj.ac/problem/2542 题解 肯定一眼 MinMax 容斥吧. 然后问题就转化为,给定一个集合 \(S\),问期望情况下多少步可以走到 \(S\) 中的点. ...

随机推荐

  1. 连接MongoDB数据库的配置说明

  2. htmlunit抓取js执行后的网页源码

    上次我不是写了一个自动抓取博客访问量吗 (点击打开链接) 可是昨天晚上我又运行的时候,发现不能用了.. 运行了几次 发现使用URLConnection 得到的网页源码和浏览器直接查看的不同. URLC ...

  3. UVa 12219 Common Subexpression Elimination (stl,模拟,实现)

    一般来说,把一颗子树离散成一个int,把一个结点的字符离散成一个int会方便处理 直接map离散.当然一个结点最多只有4个小写字母,也可以直接编码成一个27进制的整数,舍掉0,为了区分0和0000. ...

  4. URAL 1776 Anniversary Firework (概率,区间DP)

    坑,一开始以为,分成两半的时候去最大那个就行了, 实际上这样是不对的,因为有可能出现小的一半的时间比大的要长, 因为还和等待次数有关,且转移的时候需要用到次数更小的状态, 所以状态定义为二维,dp[i ...

  5. 系统学习爬虫_2_urllib

    什么是urllib urlopen urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cad ...

  6. 四、绘图可视化之Seaborn

    Seaborn-Powerful Matplotlib Extension seaborn实现直方图和密度图 import numpy as np import pandas as pd import ...

  7. 新版raspbian系统的固定IP配置和启用root账户的ssh登录功能的方法

    1. 2016新版raspbian系统的固定IP配置: 自2016年2月份新版raspbian系统发布以后,树莓派的固定IP配置方法就与之前不一样了. 之前在raspbian系统中编辑/etc/net ...

  8. js正则函数match、exec、test、search、replace、split使用集合

    match 方法 使用正则表达式模式对字符串执行查找,并将包含查找的结果作为数组返回. stringObj.match(rgExp) 参数 stringObj 必选项.对其进行查找的 String 对 ...

  9. 第五次作业:Excel制作英文课程表

    要求: 一.内外变宽线条与颜色图同,表格有底纹色彩 二.横向打印,上下左右居中,表格标题居中,表头斜线,斜线两边加文字 三.设置打开密码

  10. JS原型链(二)--new运算符的原理

    new运算符的原理: 第一步:创建一个空对象,该对象继承构造函数的原型对象 第二步:执行这个构造函数,并且把this指向该空对象 第三步:返回:如果构造函数执行后返回的结果是一个object类型,则返 ...