题意:给你一个有向图,点数10000,边数1000000,SCC大小不超过100(按数据范围的写法只有第三部分数据满足这个条件,不过第二部分数据并没有出现大小大于100个点的SCC,我是用数组大小为100的代码以身试法的2333)从s出发随机走,问走到t的期望步数.

首先考虑inf的情况.如果从s出发可以走到一个无法走到t的点,比如这个数据:红色点为起点,绿色点为终点,那么有1/2的概率永远也走不到(在蓝色点停下).

注意出现环的情况不一定是INF,因为在环上走无穷步的概率可能是无穷小。于是先缩点,把边反向找到所有不能到达t的SCC,如果从s出发有可能到达这样的一个SCC或s本身处于这样一个SCC,那么答案是INF。

接下来,我们把期望步数转化成期望经过的点数(显然经过的边数等于点数-1),那么利用期望的线性性,只需要高斯消元求出每个点的期望经过次数再加起来。但是这个范围显然不能直接做。而SCC大小小于100,提醒我们可以对每个SCC分别进行高斯消元,然后考虑SCC之间的关系。思路类似USACO一道最短路题”道路与航线”,那道题是对每个SCC分别跑dijkstra。

具体的做法:记f[i]为点i的期望经过次数,g[i]为从另一个SCC走到点i的期望次数,因为我们按拓扑序处理每个SCC,所以在处理每个SCC的时候这个SCC中每个点的g[]值都已经求出来了.接下来对SCC中每个点列一个方程.对于点x,f[x]=g[x]+sigma(f[j]/outdeg[j]),j向x有一条有向边且j和x在同一个SCC,outdeg为出度。这里j可以等于x(有自环),验证一下,这时候方程也是对的.解完这个SCC之后要用这个SCC里的点更新其他SCC的g[].注意边界g[s]=1,f[t]=1

然后码码码就好了。

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int n,m,s,t;
const int maxn=,maxm=;
//Graph Theory
struct edge{
int to,next;
}lst1[maxm],lst2[maxm],lst3[maxm];int len1=,len2=,len3=;
int first1[maxn],first2[maxn],first3[maxn];
void addedge1(int a,int b){
lst1[len1].to=b;lst1[len1].next=first1[a];
first1[a]=len1++;
}
void addedge2(int a,int b){
lst2[len2].to=b;lst2[len2].next=first2[a];
first2[a]=len2++;
}
void addedge3(int a,int b){
lst3[len3].to=b;lst3[len3].next=first3[a];
first3[a]=len3++;
}
int outdeg[maxn];
int belong[maxn],tot,sz[maxn];
vector<int> scc[maxn];
int stk[maxn],top,dfn[maxn],low[maxn],T;
bool ins[maxn];
namespace Trajan{
void dfs(int x){
low[x]=dfn[x]=++T;
stk[top++]=x;ins[x]=true;
for(int pt=first1[x];pt;pt=lst1[pt].next){
if(!dfn[lst1[pt].to]){
dfs(lst1[pt].to);
if(low[lst1[pt].to]<low[x])low[x]=low[lst1[pt].to];
}else if(ins[lst1[pt].to]&&dfn[lst1[pt].to]<low[x])low[x]=dfn[lst1[pt].to];
}
if(dfn[x]==low[x]){
++tot;
do{
ins[stk[--top]]=false;
belong[stk[top]]=tot;
scc[tot].push_back(stk[top]);
sz[tot]++;
}while(stk[top]!=x);
}
}
void tarjan(){
for(int i=;i<=n;++i){
if(!dfn[i])dfs(i);
}
for(int i=;i<=n;++i){
for(int pt=first1[i];pt;pt=lst1[pt].next){
if(belong[lst1[pt].to]!=belong[i]){
addedge2(belong[lst1[pt].to],belong[i]);
addedge3(belong[i],belong[lst1[pt].to]);
}
}
}
}
bool reachfromend[maxn],mustreachend[maxn];
void predfs(int x){
reachfromend[x]=true;
for(int pt=first2[x];pt;pt=lst2[pt].next){
if(!reachfromend[lst2[pt].to]){
predfs(lst2[pt].to);
}
}
}
bool checkdfs(int x){
if(!reachfromend[x])return false;
for(int pt=first3[x];pt;pt=lst3[pt].next){
if(mustreachend[lst3[pt].to])continue;
if(!checkdfs(lst3[pt].to))return false;
}
return mustreachend[x]=true;
}
bool check(){
predfs(belong[t]);
return checkdfs(belong[s]);
}
};
double f[maxn],g[maxn];
int map[maxn];
namespace Work{
bool done[maxn];
double F[][];
int rk;
void Swap(int a,int b){
for(int i=;i<=rk;++i)swap(F[a][i],F[b][i]);
}
void multplus(int a,int b,double times){
for(int i=;i<=rk;++i)F[a][i]+=F[b][i]*times;
}
void Gauss(int n){
rk=n;
for(int i=;i<=n;++i){
if(F[i][i]==){
for(int j=i+;j<=n;++j){
if(F[j][i]!=){
Swap(i,j);break;
}
}
}
for(int j=i+;j<=n;++j)multplus(j,i,-F[j][i]/F[i][i]);
}
for(int i=n;i>=;--i){
F[i][]/=F[i][i];
for(int j=i-;j>=;--j){
F[j][]-=F[j][i]*F[i][];
}
}
}
void build_equations(int x){
for(int i=;i<=sz[x];++i){
for(int j=;j<=sz[x];++j){
F[i][j]=;
}
}
for(int i=;i<sz[x];++i)F[i+][]=-g[scc[x][i]];
for(int i=;i<=sz[x];++i){
F[i][i]=-;map[scc[x][i-]]=i;
if(scc[x][i-]==t)F[i][]=-;
}
for(int i=;i<sz[x];++i){
if(scc[x][i]==t)continue;
for(int pt=first1[scc[x][i]];pt;pt=lst1[pt].next){
if(belong[lst1[pt].to]==x){
if(lst1[pt].to==t)continue;
F[map[lst1[pt].to]][i+]+=1.0/outdeg[scc[x][i]];
}
}
} }
void dfs(int x){
for(int pt=first2[x];pt;pt=lst2[pt].next){
if(!done[lst2[pt].to])dfs(lst2[pt].to);
}
build_equations(x);
Gauss(sz[x]);
for(int i=;i<sz[x];++i){
f[scc[x][i]]=F[i+][];
}
for(int i=;i<sz[x];++i){
for(int pt=first1[scc[x][i]];pt;pt=lst1[pt].next){
if(belong[lst1[pt].to]!=x){
g[lst1[pt].to]+=f[scc[x][i]]/outdeg[scc[x][i]];
}
}
}
done[x]=true;
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&s,&t);
int a,b;
for(int i=;i<=m;++i){
scanf("%d%d",&a,&b);addedge1(a,b);
outdeg[a]++;
}
Trajan::tarjan();
if(Trajan::check()){
g[s]=;
Work::dfs(belong[t]);
double ans=;
for(int i=;i<=n;++i){//printf("%.2f ",f[i]);
ans+=f[i];
}//ans:the expected number of points on the path from s to t
printf("%.3f\n",ans-);
}else{
printf("INF\n");
}
return ;
}

bzoj2702[SDOI2012]走迷宫的更多相关文章

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

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

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

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

  3. 【BZOJ2707】[SDOI2012]走迷宫 Tarjan+拓扑排序+高斯消元+期望

    [BZOJ2707][SDOI2012]走迷宫 Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,M ...

  4. SDOI2012 走迷宫

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

  5. bzoj 2707 [SDOI2012]走迷宫(SCC+高斯消元)

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

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

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

  7. [SDOI2012]走迷宫 (强连通分量缩点,动态规划,高斯消元)

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

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

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

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

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

随机推荐

  1. 面向云的.net core开发框架

    目录结构 1 为什么搭建面向云的.Net core云开发框架 2 主要设计思路 3 项目解决方案 4 基础设施层 4.1反射工具 4.2多级可换源的配置(上) 42多级可换源的配置(下) 4.3可配置 ...

  2. ClassNotFoundException超限

    错误日志图 被这弱智的错误吭了半个小时,项目本来好好的,然后因为改版加了很多东西,所以就超限了,一开始总是报下面那图的错,搞的我总以为是retrofit的错,但是好好的框架而且没改过,怎么可能会出错呢 ...

  3. ViewPager 重新加载 及 PagerAdapter 使用

    PagerAdapter 简介 PagerAdapter是android.support.v4包中的类,它的子类有FragmentPagerAdapter, FragmentStatePagerAda ...

  4. php foreach引用赋值

    在写代码时发现php foreach引用赋值会导致意外的行为. 代码示例: <?php $arr = array('a','b','c'); foreach($arr as $k=>&am ...

  5. jsonp跨域请求

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. AEAI ESB路由转换机制说明

    1. 背景概述 相信了解数通畅联的人对AEAI ESB并不陌生,其设计器ESBDesigner中内置组件有:路由和转换.数据适配器.协议适配器.协议接入适配器等4类组件,每类组件下面包含各种类型的组件 ...

  7. 微信调用照相拍照等 js 接口的权限配置 和 照片上传和下载实现

    直接上代码: 1. 前端调试代码: <html> <head> <meta http-equiv="Content-Type" content=&qu ...

  8. Oracle学习笔记二 初识Oracle(二)

    Windows 中的 Oracle 服务 Oracle 9i的每个实例在Windows中都作为一项服务启动 服务是在 Windows 注册表中注册的可执行进程,由 Windows 操作系统管理 “服务 ...

  9. linux命令在线手册

    下面几个网址有一些 Linux命令的在线手册,而且还是中文的,还可以搜索.非常方便 Linux命令手册 Linux命令大全 Linux中文man在线手册 每日一linux命令

  10. js异步编程技巧一

    异步回调是js的一大特性,理解好用好这个特性可以写出很高质量的代码.分享一些实际用的一些异步编程技巧. 1.我们有些应用环境是需要等待两个http请求或IO操作返回后进行后续逻辑的处理.而这种情况使用 ...