Description

Morenan被困在了一个迷宫里。迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T。可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的有向边,到达另一个点。这样,Morenan走的步数可能很长,也可能是无限,更可能到不了终点。若到不了终点,则步数视为无穷大。但你必须想方设法求出Morenan所走步数的期望值。

Input

第1行4个整数,N,M,S,T
第[2, M+1]行每行两个整数o1, o2,表示有一条从o1到o2的边。

Output

一个浮点数,保留小数点3位,为步数的期望值。若期望值为无穷大,则输出"INF"。
Sample Input
9 12 1 9
1 2
2 3
3 1
3 4
3 7
4 5
5 6
6 4
6 7
7 8
8 9
9 7
Sample Output
9.500
HINT
n<=10000,m<=1000000,保证每个强连通分量大小不超过100
 
题解
本题真的是无法描述啊......
这个高斯消元搞了我一晚上
正解其实想出来了但是就是不会打
既然题目都提示强连通分量了,肯定要跑个tarjan缩点呀
但是,经过一个强连通分量不一定就会INF,因为毕竟一次走不出去还有机会再次走出去
容易发现,INF的条件是“起点终点不连通”或“起点可以到达某个点,该点却不能到达终点”
上述INF情况可以跑正向+逆向dfs来判断
在不INF时,对于每个点,设f[i]为从i点到终点的期望步数,设du[i]为i点出度,f的方程容易想出来:
f[i]=1+sigma(f[j],i与j有边联通)/du[i]
(除了终点T,到了终点之后就不用再走了,因此f[T]=0,终点的出边也可以直接删除)
每个点的f长得和方程一样,那么我们就考虑解方程组:高斯消元
可我们发现数据范围太大(n<=10000)没办法消元
我们发现,题目提示强连通分量大小不超过100,100的范围是可以做的
因此我们考虑按照拓扑序逆序对每一个强连通分量进行高斯消元;
如果按照拓扑序逆序的话,计算某个连通块时,他会涉及到的出点都已经计算完了,所以这样是正确的
代码见下
 #include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const int N=;
const int M=;
struct node{int qi,zhong,next;}s[M],z[M],t[M];
bool vis[N],t_vis[N],z_vis[N];
int e,z_e,t_e,adj[N],z_adj[N],t_adj[N];//s最早的图,z缩点后正图,t缩点后反图
int n,m,S,T,id[N],chudu[N];//id为某个点在所属连通块
vector<int>man[N];
int dfn[N],low[N],stack[N],top,num,belong[N],tot;//tarjan相关的数组
double A[][],f[N];//A为高斯消元,f为dp数组
inline void add(int qi,int zhong)
{
s[++e].zhong=zhong;s[e].qi=qi;
s[e].next=adj[qi];adj[qi]=e;
}
inline void z_add(int qi,int zhong)
{
z[++z_e].zhong=zhong;z[z_e].qi=qi;
z[z_e].next=z_adj[qi];z_adj[qi]=z_e;
}
inline void t_add(int qi,int zhong)
{
t[++t_e].zhong=zhong;t[t_e].qi=qi;
t[t_e].next=t_adj[qi];t_adj[qi]=t_e;
}
void tarjan(int rt)
{
dfn[rt]=low[rt]=++num;
stack[++top]=rt;vis[rt]=;
for(int i=adj[rt];i;i=s[i].next)
{
int u=s[i].zhong;
if(!dfn[u])tarjan(u),low[rt]=min(low[u],low[rt]);
else if(!id[u])low[rt]=min(dfn[u],low[rt]);
}
if(dfn[rt]==low[rt])
{
int v,ge=;tot++;
do
{
v=stack[top--];id[v]=++ge;
belong[v]=tot;man[tot].push_back(v);
}
while(v!=rt);
}
}
void dfs1(int rt)
{
z_vis[rt]=;
for(int i=z_adj[rt];i;i=z[i].next)
if(!z_vis[z[i].zhong])dfs1(z[i].zhong);
}
void dfs2(int rt)
{
t_vis[rt]=;
for(int i=t_adj[rt];i;i=t[i].next)
if(!t_vis[t[i].zhong])dfs2(t[i].zhong);
}
inline bool judge()//正反dfs判断INF
{
dfs1(belong[S]);dfs2(belong[T]);
for(int i=;i<=n;i++)
if(z_vis[i]&&!t_vis[i])
return ;
return ;
}
inline void gasse(int b)//高斯消元
{ if(b==belong[T]){f[T]=;return;}
int size=man[b].size();
memset(A,,sizeof(A));
for(int i=;i<size;i++)
{
int p=man[b][i];
A[i][size]=chudu[p];//我统一把出度给乘上去了,没有写分数的形式
for(int j=adj[p];j;j=s[j].next)
{
int u=s[j].zhong;
if(belong[u]==b)//统计连通块自己的系数
A[i][id[u]-]--;
else if(u!=T)//统计之前的贡献
A[i][size]+=f[u];
}
A[i][i]+=chudu[p];
}
for(int i=;i<size;i++)
{
int p=i;
for(int j=i+;j<size;j++)
if(fabs(A[p][i])<fabs(A[j][i]))p=j;
if(p!=i)
for(int j=;j<=size;j++)
swap(A[p][j],A[i][j]);
for(int j=i+;j<size;j++)
{
double tmp=A[j][i]/A[i][i];
for(int k=i;k<=size;k++)
A[j][k]-=tmp*A[i][k];
}
}
for(int i=size-;i>=;i--)
{
for(int j=i+;j<size;j++)
A[i][size]-=A[j][size]*A[i][j];
A[i][size]/=A[i][i];
}
for(int i=;i<size;i++)
f[man[b][i]]=A[i][size];
}
void solve(int rt)
{
for(int i=z_adj[rt];i;i=z[i].next)
if(!vis[z[i].zhong])
solve(z[i].zhong);
vis[rt]=;
gasse(rt);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&S,&T);int a,b;
if(S==T){printf("0.000");return ;}
for(int i=;i<=m;i++)
{
scanf("%d%d",&a,&b);
if(a==T)continue;
chudu[a]++,add(a,b);
}
for(int i=;i<=n;i++)if(!dfn[i])tarjan(i);
for(int i=;i<=n;i++)
{
for(int j=adj[i];j;j=s[j].next)
{
int u=s[j].zhong;
if(belong[i]!=belong[u])
{
z_add(belong[i],belong[u]);
t_add(belong[u],belong[i]);
}
}
}
if(judge())
{
memset(vis,,sizeof(vis));
solve(belong[S]);
printf("%.3lf",f[S]);
}
else{printf("INF");return ;}
}

BZOJ2707

 
 
 
 

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

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

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

  2. C语言动态走迷宫

    曾经用C语言做过的动态走迷宫程序,先分享代码如下: 代码如下: //头文件 #include<stdio.h> #include<windows.h>//Sleep(500)函 ...

  3. sdut 2449走迷宫【最简单的dfs应用】

    走迷宫 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_ 题目描述 一个由n * m 个格子组成的迷宫,起点是(1, 1), 终点是(n, m) ...

  4. 洛谷P1238 走迷宫

    洛谷1238 走迷宫 题目描述 有一个m*n格的迷宫(表示有m行.n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这m*n个数据和起始点.结束点(起始点和结束点都是用两个 ...

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

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

  6. NYOJ306 走迷宫(dfs+二分搜索)

    题目描写叙述 http://acm.nyist.net/JudgeOnline/problem.php?pid=306 Dr.Kong设计的机器人卡多非常爱玩.它经常偷偷跑出实验室,在某个游乐场玩之不 ...

  7. Problem A: 走迷宫问题

    Problem A: 走迷宫问题Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 9 Solved: 3[Submit][Status][Web Board] ...

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

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

  9. P1238 走迷宫

    原题链接 https://www.luogu.org/problemnew/show/P1238 为了巩固一下刚学习的广搜,练一下迷宫类型的题 不过这道题我用的深搜..... 看问题,我们就知道这道题 ...

随机推荐

  1. Python 面向对象之一

    Python 面向对象之 类与属性 今天接触了一下面向对象,发现面向对象和之前理解的简直就是天壤之别,在学Linux的时候,一切皆文件,现在学面向对象了,so,一切皆对象. 之前不是一直在学的用面向函 ...

  2. [ext4]09 磁盘布局 - superblock备份机制

    如果sparse_super特性flag被设置(即开启了sparse_super特性),那么super_block和组描述符的副本只会保存在group索引为0或3.5.7的整数幂. 如果没有设置spa ...

  3. [Splay模版1]

    输入 第1行:1个正整数n,表示操作数量,100≤n≤200,000 第2..n+1行:可能包含下面3种规则: 1个字母'I',紧接着1个数字k,表示插入一个数字k到树中,1≤k≤1,000,000, ...

  4. windows下nodejs安装及配置

    1)在 http://nodejs.org/download/下载一个window的安装包 2)运行安装包,设置安装路径,如安装到D:\nodejs,安装后会自动将d:\nodejs添加到系统变量pa ...

  5. VopSdk一个高逼格微信公众号开发SDK

    一.我们的目标 分离基础参数和业务参数. 具有高重用和扩展性. 轻量级. 二.实现目标 (一)分离基础参数和业务参数 仔细分析所有接口,抽离出每个模块接口的公共参数. A.针对微信公众号所有接口分析( ...

  6. 微信小程序(兼容性问题)

    兼容 小程序的功能不断的增加,但是旧版本的微信客户端并不支持新功能,所以在使用这些新能力的时候需要做兼容. 文档会在组件,API等页面描述中带上各个功能所支持的版本号. 可以通过 wx.getSyst ...

  7. jquery.uploadifive 解决上传限制图片或文件大小

    dotNet疯狂之路No.28  今天很残酷,明天更残酷,后天很美好,但是绝大部分人是死在明天晚上,只有那些真正的英雄才能见到后天的太阳.  We're here to put a dent in t ...

  8. Reactjs vs. Vuejs

    欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 纪俊,从事Web前端开发工作,2016年加入腾讯OMG广告平台产品部,喜欢研究前端技术框架. 这里要讨论的话题 ...

  9. coding.net及git的使用方式

    一般部分测试的公司里可能会用到代码管理工具,这里可能不得不推荐coding.net和git这个工具,类似于svn,不过用命令行的情况多点 这里简单介绍下 1.建立coding.net 首先新建一个co ...

  10. KafKa+Zookeeper+Flume部署脚本

    喜欢学习的朋友可以收藏 愿意了解框架技术或者源码的朋友直接加求求(企鹅):2042849237