【BZOJ2707】[SDOI2012]走迷宫 Tarjan+拓扑排序+高斯消元+期望
【BZOJ2707】[SDOI2012]走迷宫
Description
Input
Output
测试点
|
N
|
M
|
Hint
|
[1, 6]
|
<=10
|
<=100
|
|
[7, 12]
|
<=200
|
<=10000
|
|
[13, 20]
|
<=10000
|
<=1000000
|
保证强连通分量的大小不超过100
|
题解:先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。
- #include <cstdio>
- #include <cstring>
- #include <iostream>
- #include <vector>
- #include <queue>
- #include <cmath>
- const int maxn=10010;
- using namespace std;
- int n,m,cnt,Cnt,tot,top,sum,S,T;
- vector<int> s[maxn];
- int dep[maxn],low[maxn],head[maxn],to[1000010],next[1000010],sta[maxn],d[maxn],ins[maxn],D[maxn],pos[maxn],bel[maxn];
- int To[1000010],Next[1000010],Head[maxn],vis[maxn];
- double p[maxn],v[110][110];
- queue<int> q;
- inline void add(int a,int b)
- {
- to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
- }
- inline void Add(int a,int b)
- {
- To[Cnt]=b,Next[Cnt]=Head[a],Head[a]=Cnt++;
- }
- void tarjan(int x)
- {
- dep[x]=low[x]=++tot,sta[++top]=x,ins[x]=1;
- int i,t;
- for(i=Head[x];i!=-1;i=Next[i])
- {
- if(!dep[To[i]]) tarjan(To[i]),low[x]=min(low[x],low[To[i]]);
- else if(ins[To[i]]) low[x]=min(low[x],dep[To[i]]);
- }
- if(dep[x]==low[x])
- {
- sum++;
- do
- {
- t=sta[top--],ins[t]=0,bel[t]=sum,pos[t]=s[sum].size(),s[sum].push_back(t);
- }while(t!=x);
- }
- }
- void calc(int x)
- {
- int i,j,k,a,b,nm=s[x].size();
- for(i=0;i<nm;i++) memset(v[i],0,sizeof(v[0][0])*(nm+1));
- for(i=0;i<nm;i++)
- {
- a=s[x][i];
- for(j=head[a];j!=-1;j=next[j])
- {
- b=to[j];
- if(bel[b]==bel[a]) v[pos[b]][pos[a]]+=1.0/d[b],v[pos[b]][nm]-=1.0/d[b];
- }
- }
- for(i=0;i<nm;i++)
- {
- v[i][nm]-=p[s[x][i]];
- if(s[x][i]==T) for(j=0;j<=nm;j++) v[i][j]=0;
- v[i][i]-=1;
- }
- for(i=0;i<nm;i++)
- {
- 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]);
- double tmp=v[i][i];
- if(fabs(tmp)<1e-9) continue;
- for(k=i;k<=nm;k++) v[i][k]/=tmp;
- for(j=0;j<nm;j++) if(i!=j)
- {
- tmp=v[j][i];
- for(k=i;k<=nm;k++) v[j][k]-=v[i][k]*tmp;
- }
- }
- for(i=0;i<nm;i++) p[s[x][i]]=v[i][nm];
- }
- void dfs(int x)
- {
- vis[x]=1;
- if(x==T) return ;
- for(int i=Head[x];i!=-1;i=Next[i])
- {
- if(bel[To[i]]!=bel[x]) D[bel[x]]++;
- if(!vis[To[i]]) dfs(To[i]);
- }
- }
- inline int rd()
- {
- int ret=0,f=1; char gc=getchar();
- while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
- while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
- return ret*f;
- }
- int main()
- {
- n=rd(),m=rd(),S=rd(),T=rd();
- int i,j,a,b,u,v;
- memset(head,-1,sizeof(head)),memset(Head,-1,sizeof(Head));
- for(i=1;i<=m;i++) a=rd(),b=rd(),Add(a,b),add(b,a),d[a]++;
- for(i=1;i<=n;i++) if(!dep[i]) tarjan(i);
- dfs(S);
- for(i=1;i<=n;i++) if(vis[i]&&bel[i]!=bel[T]&&!D[bel[i]])
- {
- printf("INF");
- return 0;
- }
- q.push(bel[T]);
- while(!q.empty())
- {
- u=q.front(),q.pop();
- calc(u);
- if(u==bel[S])
- {
- printf("%.3lf",fabs(p[S]));
- return 0;
- }
- 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])
- {
- D[bel[to[j]]]--,p[to[j]]+=(p[v]+1)/d[to[j]];
- if(!D[bel[to[j]]]) q.push(bel[to[j]]);
- }
- }
- printf("INF");
- return 0;
- }//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+拓扑排序+高斯消元+期望的更多相关文章
- HDU2262;Where is the canteen(高斯消元+期望)
传送门 题意 给出一张图,LL从一个点等概率走到上下左右位置,询问LL从宿舍走到餐厅的步数期望 分析 该题是一道高斯消元+期望的题目 难点在于构造矩阵,我们发现以下结论 设某点走到餐厅的期望为Ek 1 ...
- BZOJ2707 [SDOI2012]走迷宫 【概率dp + tarjan + 高斯消元】
题目 Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的 ...
- BZOJ2707: [SDOI2012]走迷宫(期望 tarjan 高斯消元)
题意 题目链接 Sol 设\(f[i]\)表示从\(i\)走到\(T\)的期望步数 显然有\(f[x] = \sum_{y} \frac{f[y]}{deg[x]} + 1\) 证明可以用全期望公式. ...
- BZOJ 2707: [SDOI2012]走迷宫 拓扑+高斯消元+期望概率dp+Tarjan
先Tarjan缩点 强连通分量里用高斯消元外面直接转移 注意删掉终点出边和拓扑 #include<cstdio> #include<cstring> #include<a ...
- BZOJ 2707: [SDOI2012]走迷宫( tarjan + 高斯消元 )
数据范围太大不能直接高斯消元, tarjan缩点然后按拓扑逆序对每个强连通分量高斯消元就可以了. E(u) = 1 + Σ E(v) / degree(u) 对拍时发现网上2个程序的INF判断和我不一 ...
- BZOJ2707 : [SDOI2012]走迷宫
首先求出SCC缩点,E[T]=0,按拓扑序计算 对于无边连出的块,如果不是T所在块,则称该块是死路块 对于一个块,如果其中的点连出的边是死路块,则它也是死路块 否则对于每块进行高斯消元求出期望 如果S ...
- BZOJ 3143 HNOI2013 游走 高斯消元 期望
这道题是我第一次使用高斯消元解决期望类的问题,首发A了,感觉爽爽的.... 不过笔者在做完后发现了一些问题,在原文的后面进行了说明. 中文题目,就不翻大意了,直接给原题: 一个无向连通图,顶点从1编号 ...
- 【LOJ2542】【PKUWC 2018】随机游走 min-max容斥 树上高斯消元
题目描述 有一棵 \(n\) 个点的树.你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(q\) 次询问,每次询问给定一个集合 \(S\),求如果从 \(x\) 出发一 ...
- [luogu3232 HNOI2013] 游走 (高斯消元 期望)
传送门 题目描述 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等 ...
随机推荐
- .sh文件怎么安装?
实例:sh java_1.8.0.sh示例:sh filename.sh
- 几个opengl立方体绘制案例
VC6 下载 http://blog.csdn.net/bcbobo21cn/article/details/44200205 opengl环境配置 http://blog.csdn.net/bcbo ...
- web 前端 常见操作 将时间戳转成日期格式 字符串截取 使用mui制作选项卡
1.将时间戳转成日期格式: //第一种 function getLocalTime(nS) { return new Date(parseInt(nS) * 1000).toLocaleString( ...
- 《从零開始学Swift》学习笔记(Day 57)——Swift编码规范之凝视规范:文件凝视、文档凝视、代码凝视、使用地标凝视
原创文章.欢迎转载.转载请注明:关东升的博客 前面说到Swift凝视的语法有两种:单行凝视(//)和多行凝视(/*...*/).这里来介绍一下他们的使用规范. 1.文件凝视 文件凝视就在每个文件开头加 ...
- javascript 清空数组的方法
1,splice var ary = [1,2,3,4]; ary.splice(0,ary.length); console.log(ary); // 输出 [],空数组,即被清空了 2,lengt ...
- Python 中实现装饰器时使用 @functools.wraps 的理由
Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过 ...
- Asp.Net WebApi服务端解决跨域方案
1.特性方式 主要是继承ActionFilterAttribute,重写OnActionExecuted方法,在action执行后,给响应头加上一个键值对. using System.Web.Http ...
- 一个文件查看你选择 Run as Android applications 都干了啥
<?xml version="1.0" encoding="UTF-8"?> <project name="PushFastDemo ...
- modelsim显示状态机名称的方法
modelsim显示状态机名称的方法 2015-09-08 15:35 1414人阅读 评论(0) 收藏 举报 分类: FPGA基础知识(40) 版权声明:转载请注明出处:http://blog. ...
- SDRAM驱动篇之简易SDRAM控制器的verilog代码实现
在Kevin写的上一篇博文<SDRAM理论篇之基础知识及操作时序>中,已经把SDRAM工作的基本原理和SDRAM初始化.读.写及自动刷新操作的时序讲清楚了,在这一片博文中,Kevin来根据 ...