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\) 证明可以用全期望公式. ...
随机推荐
- arcgis api for js入门开发系列三地图工具栏(含源代码)
上一篇实现了demo的地图加载展示,在上篇实现的基础上,新增了地图工具栏以及通用地图控件功能,比如地图框选缩放.地图漫游.清空.量算工具.地图导航控件.地图比例尺控件.地图鹰眼图等等,总共分为5个部分 ...
- 用NSAttributedString实现简单的图文混排
iOS7以后,因为TextKit的强大,可以用NSAttributedString很方便的实现图文混排(主要是利用了NSTextAttachment). 关于Textkit的牛逼之处,可以参考objc ...
- iOS获取app图标和启动图片名字(AppIcon and LaunchImage's name)
在某种场景下,可能我们需要获取app的图标名称和启动图片的名称.比如说app在前台时,收到了远程通知但是通知栏是不会有通知提醒的,这时我想做个模拟通知提示,需要用到icon名称:再比如在加载某个控制器 ...
- 鹏程网用户管理系统学习(2016-07-18 by 徐鹏)
新的平台:X平台(x.hna.net)旧的平台:鹏程网(www.hna.net) 如今的平台情况:很多业务已经转到X平台,但也存在少量的业务还是用鹏程网的旧系统.例如**用户管理系统(也逐渐转移到易服 ...
- hdfs以及hbase动态增加和删除节点
一个知乎上的问题:Hbase的Region server和hadoop的datanode是否可以部署在一台服务器上?如果是的话,二者是否是一对一的关系?部署在同一台服务器上,可以减少数据跨网络传输的流 ...
- 机器学习实战笔记(Python实现)-07-分类性能度量指标
1.混淆矩阵 下图是一个二类问题的混淆矩阵,其中的输出采用了不同的类别标签 常用的衡量分类性能的指标有: 正确率(Precision),它等于 TP/(TP+FP) ,给出的是预测为正例的样本中的真正 ...
- Oracle学习笔记八 表空间
表空间 表空间是一个或多个数据文件的集合,所有的数据对象都存放在指定的表空间中,但主要存放的是表, 所以称作表空间 . 分区表 当表中的数据量不断增大,查询数据的速度就会变慢,应用程序的性能就会下 ...
- Web site collections
Integration 伯乐在线 极客头条 Hacker News Stack Overflow RFC Search Security Python Hacker - Freebuf PrimalS ...
- 国际化(Internationalization)
1:什么是国际化? 国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式.它要求从产品中抽离所有的与语言,国家/地区和文化相关的元素.换言之,应用程序的功 ...
- SpringMVC注解开发初步
一.(补充)视图解析器---XmlViewResolver 作用:分离配置信息. 在视图解析器---BeanNameViewResolver的基础之上进行扩充,新建一个myView.xml分离信息 在 ...