BZOJ.2707.[SDOI2012]走迷宫(期望 Tarjan 高斯消元)
一个点到达终点的期望步数 \(E_i=\sum_{(i,j)\in G}\frac{E_j+1}{out[i]}\),\(out[i]\)为点\(i\)的出度。
那么对于一个DAG可以直接在反向图上拓扑+DP求解。
于是对于环内高斯消元,缩点后拓扑+DP。
无解(无限步)的情况: 起点到不了终点;起点能够走到一个环,且在这个环内无法走到终点(走不出去)。
ps:1.T连出的边不能计算。
2.期望的计算式有个+1!
3.建反向边!
4.重边
注:
如果\(E_i\)表示从起点到点\(i\)的期望步数,那么起点可能多次到达点\(i\),\(E_i\)这个值就。。(可以就直接拿起点做例子?)
如果\(E_i\)表示到达终点的期望步数就没有这个问题。
//21136kb 5168ms
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
const int N=1e4+5,M=1e6+5;
int n,m,S,T,Enum,H[N],to[M],nxt[M],_H[N],_to[M],_nxt[M],in[N],q[N];
int tot,bel[N],scc[N][103],num[N],sz[N],Index,dfn[N],low[N],sk[N],top;
double A[105][105],E[N],out[N];
bool vis[N],vis_s[N],exist[N];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AddEdge(int u,int v){
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
_to[Enum]=u, _nxt[Enum]=_H[v], _H[v]=Enum;
}
void Tarjan(int x)
{
dfn[x]=low[x]=++Index, sk[++top]=x, exist[x]=1;
for(int i=H[x]; i; i=nxt[i])
if(!dfn[to[i]]) Tarjan(to[i]),low[x]=std::min(low[x],low[to[i]]);
else if(exist[to[i]]) low[x]=std::min(low[x],dfn[to[i]]);
if(dfn[x]==low[x])
{
++tot;
do
{
bel[sk[top]]=tot, num[sk[top]]=sz[tot],
scc[tot][sz[tot]++]=sk[top], exist[sk[top--]]=0;
}while(sk[top+1]!=x);
}
}
void DFS(int x)
{
vis[x]=vis_s[bel[x]]=1;
if(x==T) return;//有没有都行
for(int i=H[x]; i; i=nxt[i])
if(!vis[to[i]]) /*++in[bel[x]],//Wrong*/DFS(to[i]);
}
void Gauss(int n)
{
for(int j=0; j<n; ++j)
{
int mxrow=j;
for(int i=j+1; i<n; ++i)
if(fabs(A[i][j])>fabs(A[mxrow][j])) mxrow=i;
if(mxrow!=j) for(int k=0; k<=n; ++k) std::swap(A[mxrow][k],A[j][k]);
for(int i=j+1; i<n; ++i)
if(A[i][j])
{
double t=A[i][j]/A[j][j];
for(int k=j; k<=n; ++k)
A[i][k]-=A[j][k]*t;
}
}
for(int i=n-1; ~i; --i)
{
for(int j=i+1; j<n; ++j) A[i][n]-=A[i][j]*A[j][n];
A[i][n]/=A[i][i];
}
}
int main()
{
n=read(),m=read(),S=read(),T=read();
for(int u,v,i=1; i<=m; ++i) u=read(),v=read(),out[u]+=1.0,AddEdge(u,v);
for(int i=1; i<=n; ++i)
if(!dfn[i]) Tarjan(i);
DFS(S);
if(!vis[T]) {puts("INF"); return 0;}
for(int x=1; x<=n; ++x)
for(int i=H[x]; i; i=nxt[i])
if(bel[x]!=bel[to[i]]) ++in[bel[x]];//反向图上的入度+1。
for(int i=1; i<=tot; ++i)
if(vis_s[i]&&!in[i]&&bel[T]!=i) {puts("INF"); return 0;}
for(int i=1; i<=n; ++i) out[i]=1.0/out[i];
int h=0,t=0;
q[t++]=bel[T];
// for(int i=1; i<=tot; ++i)
// if(!in[i]) q[t++]=i;//in[]=0的只能是bel[T].
while(h<t)
{
int now=q[h++];
memset(A,0,sizeof A);
for(int j=0; j<sz[now]; ++j)
{
int x=scc[now][j];
A[j][j]=1.0, A[j][sz[now]]=E[x]/*之前加上的*/;
if(x==T) continue;//不计算终点连出的边!
for(int i=H[x]; i; i=nxt[i])
if(bel[to[i]]==now){
A[j][sz[now]]+=out[x],//步数+1.
A[j][num[to[i]]]-=out[x];//是点的出度不是in[]! //-=不能直接赋值=:有重边!
}
}
Gauss(sz[now]);
for(int j=0; j<sz[now]; ++j)
{
int x=scc[now][j];
E[x]=A[j][sz[now]];
for(int i=_H[x]; i; i=_nxt[i])
if(bel[_to[i]]!=now){
if(!--in[bel[_to[i]]]) q[t++]=bel[_to[i]];
E[_to[i]]+=(E[x]+1)*out[_to[i]];
}
}
}
printf("%.3lf",E[S]);
return 0;
}
BZOJ.2707.[SDOI2012]走迷宫(期望 Tarjan 高斯消元)的更多相关文章
- bzoj 2707 [SDOI2012]走迷宫(SCC+高斯消元)
Description 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_3143_[Hnoi2013]游走_期望DP+高斯消元
BZOJ_3143_[Hnoi2013]游走_期望DP+高斯消元 题意: 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机 ...
- BZOJ 2707: [SDOI2012]走迷宫( tarjan + 高斯消元 )
数据范围太大不能直接高斯消元, tarjan缩点然后按拓扑逆序对每个强连通分量高斯消元就可以了. E(u) = 1 + Σ E(v) / degree(u) 对拍时发现网上2个程序的INF判断和我不一 ...
- BZOJ 2707: [SDOI2012]走迷宫 [高斯消元 scc缩点]
2707: [SDOI2012]走迷宫 题意:求s走到t期望步数,\(n \le 10^4\),保证\(|SCC| \le 100\) 求scc缩点,每个scc高斯消元,scc之间直接DP 注意每次清 ...
- BZOJ 2707: [SDOI2012]走迷宫 拓扑+高斯消元+期望概率dp+Tarjan
先Tarjan缩点 强连通分量里用高斯消元外面直接转移 注意删掉终点出边和拓扑 #include<cstdio> #include<cstring> #include<a ...
- bzoj千题计划289:bzoj 2707: [SDOI2012]走迷宫
http://www.lydsy.com/JudgeOnline/problem.php?id=2707 dp[i] 表示从点i到终点的期望步数 dp[i]= Σ (dp[j]+1)/out[i] j ...
- ZJUT 1423 地下迷宫(期望DP&高斯消元)
地下迷宫 Time Limit:1000MS Memory Limit:32768K Description: 由于山体滑坡,DK被困在了地下蜘蛛王国迷宫.为了抢在DH之前来到TFT,DK必须尽快走 ...
- BZOJ 4820 [Sdoi2017]硬币游戏 ——期望DP 高斯消元
做法太神了,理解不了. 自己想到的是建出AC自动机然后建出矩阵然后求逆计算,感觉可以过$40%$ 用一个状态$N$表示任意一个位置没有匹配成功的概率和. 每种匹配不成功的情况都是等价的. 然后我们强制 ...
随机推荐
- JS实现双击内容变为可编辑状态
在一些网站上我们经常看到交互性很强的功能.一些用户资料可以直接双击出现文本框,并在此输入新的资料即可修改,无需再按确定按钮等.. 我在网上查了很多资料,但都有一个小bug,就是当获取焦点后,光标的位置 ...
- 【转】C++的const类成员函数
我们知道,在C++中,若一个变量声明为const类型,则试图修改该变量的值的操作都被视编译错误.例如, const char blank=' '; blank='\n'; //错误 面向对象程序设计中 ...
- 深入解析内存原理:DRAM的基本原理
前面我们知道了在一个简单的SRAM 芯片中进行读写操作的步骤了,然后我们来了解一下普通的DRAM 芯片的工作情况.DRAM 相对于SRAM 来说更加复杂,因为在DRAM存储数据的过程中需要对于存储的信 ...
- oracle 监听 添加ip
同时修改tnsnames.ora.listener.ora将这两个文件中HOST后面的主机都修改为127.0.0.1然后重启OracleServiceXE.OracleXETNSListener服务 ...
- Linux中断处理(二)
与Linux设备驱动中中断处理相关的首先是申请与释放IRQ的API request_irq()和free_irq(),request_irq()的原型为:int request_irq(unsigne ...
- Expm 1_3 数组中逆序对个数问题
有一个数的序列A[1].A[2] .A[3] .…… .A[n],若i<j,并且A[i]>A[j],则称A[i]与A[j]构成了一个逆序对,设计算法求数列A中逆序对的个数. package ...
- Spring整合strus2简单应用总结
本身strus2没接触过,所以这块学的一知半解,正常不整合的还没学(接着学) step: 1.创建web工程 2.在/WEB-INF/lib引入jar包 asm-3.3.jarasm-commons- ...
- [学习笔记]Javascript的包装对象
例子1: var s="test"; s.len = 4; var t = s.len // t is undefined 原因是s是字符串,第二行代码,实际上是创建一个临时字符串 ...
- pyspark遇到报错:_PYSPARK_DRIVER_CONN_INFO_PATH
1. 环境 : centos,启动pyspark,执行如下python命令: import pyspark from pyspark import SparkContext from pyspark ...
- winform(记事本的打印)