【BZOJ2707】[SDOI2012]走迷宫

Description

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

Input

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

Output

一个浮点数,保留小数点3位,为步数的期望值。若期望值为无穷大,则输出"INF"。
【样例输入1】
6 6 1 6
1 2
1 3
2 4
3 5
4 6
5 6
【样例输出1】
3.000
【样例输入2】
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
【样例输出2】
9.500
【样例输入3】
2 0 1 2
【样例输出3】
INF
【数据范围】
测试点
N
M
Hint
[1, 6]
<=10
<=100
 
[7, 12]
<=200
<=10000
 
[13, 20]
<=10000
<=1000000
保证强连通分量的大小不超过100
 
 
另外,均匀分布着40%的数据,图中没有环,也没有自环

题解:先Tarjan缩环,然后对于强连通分量内部的点,用高斯消元,外部的DAG用拓扑排序+DP。具体细节还是说一下吧:
1.高斯消元时,列方程$f[i]=\sum f[j]/d[i]+1$,发现i的某些出边可能指向强连通分量外的点,把它们都当成常数项就好了。特别地,T的方程要特殊处理。
2.判断INF时比较坑,从S开始BFS,我们的DAG只能包含我们能DFS到的点,并且,搜到T时要立刻停止。DFS后,如果发现一个强连通分量的出度为0且不是T所在的强连通分量,则INF。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <vector>
  5. #include <queue>
  6. #include <cmath>
  7. const int maxn=10010;
  8. using namespace std;
  9. int n,m,cnt,Cnt,tot,top,sum,S,T;
  10. vector<int> s[maxn];
  11. int dep[maxn],low[maxn],head[maxn],to[1000010],next[1000010],sta[maxn],d[maxn],ins[maxn],D[maxn],pos[maxn],bel[maxn];
  12. int To[1000010],Next[1000010],Head[maxn],vis[maxn];
  13. double p[maxn],v[110][110];
  14. queue<int> q;
  15. inline void add(int a,int b)
  16. {
  17. to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
  18. }
  19. inline void Add(int a,int b)
  20. {
  21. To[Cnt]=b,Next[Cnt]=Head[a],Head[a]=Cnt++;
  22. }
  23. void tarjan(int x)
  24. {
  25. dep[x]=low[x]=++tot,sta[++top]=x,ins[x]=1;
  26. int i,t;
  27. for(i=Head[x];i!=-1;i=Next[i])
  28. {
  29. if(!dep[To[i]]) tarjan(To[i]),low[x]=min(low[x],low[To[i]]);
  30. else if(ins[To[i]]) low[x]=min(low[x],dep[To[i]]);
  31. }
  32. if(dep[x]==low[x])
  33. {
  34. sum++;
  35. do
  36. {
  37. t=sta[top--],ins[t]=0,bel[t]=sum,pos[t]=s[sum].size(),s[sum].push_back(t);
  38. }while(t!=x);
  39. }
  40. }
  41. void calc(int x)
  42. {
  43. int i,j,k,a,b,nm=s[x].size();
  44. for(i=0;i<nm;i++) memset(v[i],0,sizeof(v[0][0])*(nm+1));
  45. for(i=0;i<nm;i++)
  46. {
  47. a=s[x][i];
  48. for(j=head[a];j!=-1;j=next[j])
  49. {
  50. b=to[j];
  51. if(bel[b]==bel[a]) v[pos[b]][pos[a]]+=1.0/d[b],v[pos[b]][nm]-=1.0/d[b];
  52. }
  53. }
  54. for(i=0;i<nm;i++)
  55. {
  56. v[i][nm]-=p[s[x][i]];
  57. if(s[x][i]==T) for(j=0;j<=nm;j++) v[i][j]=0;
  58. v[i][i]-=1;
  59. }
  60. for(i=0;i<nm;i++)
  61. {
  62. for(j=i+1;j<nm;j++) if(fabs(v[j][i])>fabs(v[i][i])) for(k=i;k<=nm;k++) swap(v[j][k],v[i][k]);
  63. double tmp=v[i][i];
  64. if(fabs(tmp)<1e-9) continue;
  65. for(k=i;k<=nm;k++) v[i][k]/=tmp;
  66. for(j=0;j<nm;j++) if(i!=j)
  67. {
  68. tmp=v[j][i];
  69. for(k=i;k<=nm;k++) v[j][k]-=v[i][k]*tmp;
  70. }
  71. }
  72. for(i=0;i<nm;i++) p[s[x][i]]=v[i][nm];
  73. }
  74. void dfs(int x)
  75. {
  76. vis[x]=1;
  77. if(x==T) return ;
  78. for(int i=Head[x];i!=-1;i=Next[i])
  79. {
  80. if(bel[To[i]]!=bel[x]) D[bel[x]]++;
  81. if(!vis[To[i]]) dfs(To[i]);
  82. }
  83. }
  84. inline int rd()
  85. {
  86. int ret=0,f=1; char gc=getchar();
  87. while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
  88. while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
  89. return ret*f;
  90. }
  91. int main()
  92. {
  93. n=rd(),m=rd(),S=rd(),T=rd();
  94. int i,j,a,b,u,v;
  95. memset(head,-1,sizeof(head)),memset(Head,-1,sizeof(Head));
  96. for(i=1;i<=m;i++) a=rd(),b=rd(),Add(a,b),add(b,a),d[a]++;
  97. for(i=1;i<=n;i++) if(!dep[i]) tarjan(i);
  98. dfs(S);
  99. for(i=1;i<=n;i++) if(vis[i]&&bel[i]!=bel[T]&&!D[bel[i]])
  100. {
  101. printf("INF");
  102. return 0;
  103. }
  104. q.push(bel[T]);
  105. while(!q.empty())
  106. {
  107. u=q.front(),q.pop();
  108. calc(u);
  109. if(u==bel[S])
  110. {
  111. printf("%.3lf",fabs(p[S]));
  112. return 0;
  113. }
  114. for(i=0;i<(int)s[u].size();i++) for(v=s[u][i],j=head[v];j!=-1;j=next[j]) if(bel[to[j]]!=bel[v])
  115. {
  116. D[bel[to[j]]]--,p[to[j]]+=(p[v]+1)/d[to[j]];
  117. if(!D[bel[to[j]]]) q.push(bel[to[j]]);
  118. }
  119. }
  120. printf("INF");
  121. return 0;
  122. }//9 12 1 6 1 2 2 3 3 1 3 4 3 7 4 5 5 6 6 4 6 7 7 8 8 9 9 7

【BZOJ2707】[SDOI2012]走迷宫 Tarjan+拓扑排序+高斯消元+期望的更多相关文章

  1. HDU2262;Where is the canteen(高斯消元+期望)

    传送门 题意 给出一张图,LL从一个点等概率走到上下左右位置,询问LL从宿舍走到餐厅的步数期望 分析 该题是一道高斯消元+期望的题目 难点在于构造矩阵,我们发现以下结论 设某点走到餐厅的期望为Ek 1 ...

  2. BZOJ2707 [SDOI2012]走迷宫 【概率dp + tarjan + 高斯消元】

    题目 Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的 ...

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

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

  4. BZOJ 2707: [SDOI2012]走迷宫 拓扑+高斯消元+期望概率dp+Tarjan

    先Tarjan缩点 强连通分量里用高斯消元外面直接转移 注意删掉终点出边和拓扑 #include<cstdio> #include<cstring> #include<a ...

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

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

  6. BZOJ2707 : [SDOI2012]走迷宫

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

  7. BZOJ 3143 HNOI2013 游走 高斯消元 期望

    这道题是我第一次使用高斯消元解决期望类的问题,首发A了,感觉爽爽的.... 不过笔者在做完后发现了一些问题,在原文的后面进行了说明. 中文题目,就不翻大意了,直接给原题: 一个无向连通图,顶点从1编号 ...

  8. 【LOJ2542】【PKUWC 2018】随机游走 min-max容斥 树上高斯消元

    题目描述 有一棵 \(n\) 个点的树.你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(q\) 次询问,每次询问给定一个集合 \(S\),求如果从 \(x\) 出发一 ...

  9. [luogu3232 HNOI2013] 游走 (高斯消元 期望)

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

随机推荐

  1. .sh文件怎么安装?

    实例:sh java_1.8.0.sh示例:sh filename.sh

  2. 几个opengl立方体绘制案例

    VC6 下载 http://blog.csdn.net/bcbobo21cn/article/details/44200205 opengl环境配置 http://blog.csdn.net/bcbo ...

  3. web 前端 常见操作 将时间戳转成日期格式 字符串截取 使用mui制作选项卡

    1.将时间戳转成日期格式: //第一种 function getLocalTime(nS) { return new Date(parseInt(nS) * 1000).toLocaleString( ...

  4. 《从零開始学Swift》学习笔记(Day 57)——Swift编码规范之凝视规范:文件凝视、文档凝视、代码凝视、使用地标凝视

    原创文章.欢迎转载.转载请注明:关东升的博客 前面说到Swift凝视的语法有两种:单行凝视(//)和多行凝视(/*...*/).这里来介绍一下他们的使用规范. 1.文件凝视 文件凝视就在每个文件开头加 ...

  5. javascript 清空数组的方法

    1,splice var ary = [1,2,3,4]; ary.splice(0,ary.length); console.log(ary); // 输出 [],空数组,即被清空了 2,lengt ...

  6. Python 中实现装饰器时使用 @functools.wraps 的理由

    Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过  ...

  7. Asp.Net WebApi服务端解决跨域方案

    1.特性方式 主要是继承ActionFilterAttribute,重写OnActionExecuted方法,在action执行后,给响应头加上一个键值对. using System.Web.Http ...

  8. 一个文件查看你选择 Run as Android applications 都干了啥

    <?xml version="1.0" encoding="UTF-8"?> <project name="PushFastDemo ...

  9. modelsim显示状态机名称的方法

    modelsim显示状态机名称的方法 2015-09-08 15:35 1414人阅读 评论(0) 收藏 举报  分类: FPGA基础知识(40)  版权声明:转载请注明出处:http://blog. ...

  10. SDRAM驱动篇之简易SDRAM控制器的verilog代码实现

    在Kevin写的上一篇博文<SDRAM理论篇之基础知识及操作时序>中,已经把SDRAM工作的基本原理和SDRAM初始化.读.写及自动刷新操作的时序讲清楚了,在这一片博文中,Kevin来根据 ...