bzoj2702[SDOI2012]走迷宫
题意:给你一个有向图,点数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]走迷宫的更多相关文章
- 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 注意每次清 ...
- 【BZOJ2707】[SDOI2012]走迷宫 Tarjan+拓扑排序+高斯消元+期望
[BZOJ2707][SDOI2012]走迷宫 Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,M ...
- SDOI2012 走迷宫
走迷宫 Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发 ...
- bzoj 2707 [SDOI2012]走迷宫(SCC+高斯消元)
Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿 ...
- BZOJ2707 [SDOI2012]走迷宫 【概率dp + tarjan + 高斯消元】
题目 Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的 ...
- [SDOI2012]走迷宫 (强连通分量缩点,动态规划,高斯消元)
题面 Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的 ...
- BZOJ.2707.[SDOI2012]走迷宫(期望 Tarjan 高斯消元)
题目链接 一个点到达终点的期望步数 \(E_i=\sum_{(i,j)\in G}\frac{E_j+1}{out[i]}\),\(out[i]\)为点\(i\)的出度. 那么对于一个DAG可以直接在 ...
- BZOJ2707: [SDOI2012]走迷宫(期望 tarjan 高斯消元)
题意 题目链接 Sol 设\(f[i]\)表示从\(i\)走到\(T\)的期望步数 显然有\(f[x] = \sum_{y} \frac{f[y]}{deg[x]} + 1\) 证明可以用全期望公式. ...
随机推荐
- Maven+Spring+Spring MVC+MyBatis+MySQL,搭建SSM框架环境【转】
项目建设完成之后的结构: 数据库的表结构如下: 环境建设:搭建Maven环境.Tomcat环境.需要MySql 数据库支持,使用的编程工具Eclipse (这些是前期准备): 开始创建工程: 1.创建 ...
- ipython notebook 浏览器中编写数学公式和现实
Python Notebook简介1 http://www.cnblogs.com/cbscan/p/3545084.html $ python -m IPython http://pypi.pyth ...
- iOS开发中的数学函数
在iOS开发当中...我们往往会涉及到一些算法...为了节省一些时间...让APP很快地被开发出来...我们需要对各类函数有一定的了解...接下来...我把部分常用函数分享出来...希望能帮到大家.. ...
- iOS中空字符串报错
*参考: http://www.ithao123.cn/content-8030945.html *参考: http://www.cnblogs.com/ziyi--caolu/p/4825633.h ...
- swift学习笔记5——其它部分(自动引用计数、错误处理、泛型...)
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- H5 表格标签基本使用
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 解析Jquery取得iframe中元素的几种方法
iframe在复合文档中经常用到,利用jquery操作iframe可以大幅提高效率,这里收集一些基本操作,需要的朋友可以参考下 DOM方法:父窗口操作IFRAME:window.frames[&q ...
- ORACLE推导参数Derived Parameter介绍
Oracle的推导参数(Derived Parameters)其实是初始化参数的一种.推导参数值通常来自于其它参数的运算,依赖其它参数计算得出.官方文档关于推导参数(Derived Parameter ...
- C#语句2——循环语句(for循环与for循环嵌套)
循环:反复执行某段代码. 循环四要素:初始条件,循环条件,循环体,状态改变. for(初始条件;循环条件;状态改变) { 循环体 } break ——中断循环,跳出整个循环 continue——停止本 ...
- 常用算法——排序(一)
排序(Sort)是计算机程序设计中的一种重要操作,也是日常生活中经常遇到的问题.例如,字典中的单词是以字母的顺序排列,否则,使用起来非常困难.同样,存储在计算机中的数据的次序,对于处理这些数据的算法的 ...