Portal --> bzoj2707

Solution

  首先题目有一个十分明显的暗示。。强联通分量。。那肯定就是要tarjan一波咯

  先看看什么情况下会\(INF\),其实就是题目里面讲的两种:

  一种是根本走不到出口,一种是存在一个点,起点能够走到这个点但是这个点走不到出口

  具体判断方式的话分别从起点和出口跑两遍dfs就好了

​  

  对于不是\(INF\)的情况,考虑用dp来算到达每个点的期望步数

  用\(f[i]\)表示\(i\)走到终点的期望步数,\(du[i]\)表示\(i\)点的出度,对于不为出口的点,可以得到式子

\[f[i]=1+\sum f[u]*\frac{1}{du[i]}
\]

  其中\(u\)满足原图中存在一条\((i,u)\)的边

  对于出口\(T\)则有\(f[T]=0\)

  然后每个点的式子是一样的,我们把\(f[i]\)看成未知数,就可以考虑用高斯消元解方程组来解决问题

  然而很尴尬的事情是\(n<=10000\),直接消元愉快爆炸qwq

  

  注意到题目那个给的很奇怪的条件:强联通分量的大小\(<=100\),而对于\(100\)的规模是可以高斯消元的

  所以我们可以将图中的强联通分量分别缩点,然后对每个强联通分量消元

  那对于一个强联通分量里面直接消消不出来的未知数怎么办呢?我们考虑按照一个特定的顺序来处理每个强联通分量,也就是按照缩点后的拓扑序逆序来消,这样可以保证到消到一个强联通分量的时候,里面涉及到的连出去的点的\(f\)值已经被处理出来了,方程数量和包含的未确定的\(f\)值的数量相同,这样在消元的时候就不会出现问题了

​  

  代码大概长这样(小trick在消元的时候两边乘上出度把分母搞掉会比较舒服一点)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#define db double
using namespace std;
const int MAXN=10010;
struct xxx{
int y,nxt;
}a[1000010*2];
int h[MAXN],viscnt[MAXN],vis[MAXN],dfn[MAXN],low[MAXN];
int id[MAXN],belong[MAXN];
int st[MAXN],inst[MAXN],ind[MAXN],outd[MAXN],nind[MAXN],noutd[MAXN];
vector<int>dian[MAXN],na[MAXN],ina[MAXN];
db A[110][110],f[MAXN];
int n,m,tot,T,num,dfn_t,top,S,visT;
void add(int x,int y);
void dfs(int x);
void tarjan(int x);
void prework();
bool check();
void checkdfs1(int x);
void checkdfs2(int x);
void solve();
void solvedfs(int x);
void gauss(int b);
void fill(int b); int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x,y;
scanf("%d%d%d%d",&n,&m,&S,&T);
memset(h,-1,sizeof(h));
tot=0;
for (int i=1;i<=m;++i){
scanf("%d%d",&x,&y);
if (x==T) continue;
++ind[y]; ++outd[x];
add(x,y);
}
prework();
solve();
} void prework(){
num=0;
for (int i=1;i<=n;++i)
if (dfn[i]==0) tarjan(i);
int u;
for (int i=1;i<=n;++i){
for (int j=h[i];j!=-1;j=a[j].nxt){
u=a[j].y;
if (belong[i]!=belong[u]){
na[belong[i]].push_back(belong[u]);
ina[belong[u]].push_back(belong[i]);
}
}
}
} void add(int x,int y){
a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;
} void tarjan(int x){
int u;
dfn[x]=++dfn_t; low[x]=dfn[x]; st[++top]=x; inst[x]=true;
for (int i=h[x];i!=-1;i=a[i].nxt){
u=a[i].y;
if (dfn[u]==0){
tarjan(u);
low[x]=min(low[u],low[x]);
}
else if (inst[u])
low[x]=min(low[x],dfn[u]);
}
if (low[x]==dfn[x]){
++num;
int tmpcnt=0;
do{
u=st[top--]; inst[u]=false;
id[u]=++tmpcnt; nind[num]+=ind[u]; noutd[num]+=outd[u];
belong[u]=num;
dian[num].push_back(u);
}while (u!=x);
}
} void checkdfs1(int x){
int u;
++viscnt[x]; vis[x]=visT;
for (int i=0;i<na[x].size();++i)
if (vis[na[x][i]]!=visT)
checkdfs1(na[x][i]);
} void checkdfs2(int x){
int u;
viscnt[x]+=2; vis[x]=visT;
for (int i=0;i<ina[x].size();++i)
if (vis[ina[x][i]]!=visT)
checkdfs2(ina[x][i]);
} bool check(){
memset(vis,0,sizeof(vis));
++visT; checkdfs1(belong[S]);
++visT; checkdfs2(belong[T]);
for (int i=1;i<=num;++i) if (viscnt[i]==1) return false;
return true;
} void solve(){
if (!check()){printf("INF\n");return;}
++visT;
solvedfs(belong[S]);
printf("%.3lf\n",f[S]);
} void solvedfs(int x){
vis[x]=visT;
for (int i=0;i<na[x].size();++i)
if (vis[na[x][i]]!=visT)
solvedfs(na[x][i]);
gauss(x);
} void fill(int b){
int sz=dian[b].size(),x,u;
memset(A,0,sizeof(A));
for (int i=0;i<sz;++i){
x=dian[b][i];
A[i][sz]=1*outd[x];//all *outd[x];
for (int j=h[x];j!=-1;j=a[j].nxt){
u=a[j].y;
if (belong[u]==b)
A[i][id[u]-1]--;
else
A[i][sz]+=f[u];
}
A[i][i]+=outd[x];
}
} void gauss(int b){
if (b==belong[T]){f[T]=0; return;}
fill(b);
int id,n=dian[b].size();
db tmp;
for (int i=0;i<n;++i){
id=i;
for (int j=i+1;j<n;++j)
if (fabs(A[j][i])>fabs(A[id][i])) id=j;
if (id!=i)
for (int j=0;j<=n;++j) swap(A[id][j],A[i][j]);
for (int j=i+1;j<n;++j){
tmp=A[j][i]/A[i][i];
for (int k=i;k<=n;++k)
A[j][k]-=tmp*A[i][k];
}
}
for (int i=n-1;i>=0;--i){
for (int j=n-1;j>i;--j)
A[i][n]-=A[i][j]*A[j][n];
A[i][n]/=A[i][i];
}
for (int i=0;i<n;++i)
f[dian[b][i]]=A[i][n];
}

【bzoj2707】走迷宫的更多相关文章

  1. [BZOJ2707]走迷宫

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

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

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

  3. C语言动态走迷宫

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

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

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

  5. 洛谷P1238 走迷宫

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

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

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

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

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

  8. Problem A: 走迷宫问题

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

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

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

  10. P1238 走迷宫

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

随机推荐

  1. tensorflow中tensor与数组之间的转换

    # 主要是两个方法: # 1.数组转tensor:数组a, tensor_a=tf.convert_to_tensor(a) # 2.tensor转数组:tensor b, array_b=b.eva ...

  2. Amazon移除差评适用范围 - Amazon request for the feedback removal

    Greetings from Amazon Seller Support, Please accept my sincere apologies for the inconvenience cause ...

  3. BZOJ 1901 Zju2112 Dynamic Rankings 树状数组套线段树

    题意概述:带修改求区间第k大. 分析: 我们知道不带修改的时候直接上主席树就可以了对吧?两个版本号里面的节点一起走在线段树上二分,复杂度是O((N+M)logN). 然而这里可以修改,主席树显然是凉了 ...

  4. ECharts模块化使用5分钟上手

    什么是EChats? 一句话: 一个数据可视化(图表)Javascript框架,详细?移步这里,类似(推荐)的有 HighCharts,其他? 嗯,先看看吧-- 快速上手: 模块化单文件引入(推荐). ...

  5. LCA(Tarjan算法)模板

    一.查询一组的LCA Nearest Common Ancestors A rooted tree is a well-known data structure in computer science ...

  6. SQL连接的方法

    1.创建连接字符串 string con = "Data Source=127.0.0.1;Initial Catalog=dingdan;Integrated Security=True& ...

  7. 《JavaScript设计模式与开发实践》——第3章 闭包和高阶函数

    闭包 变量的作用域和生存周期密切相关 高阶函数 函数可以作为参数被传递 函数可以作为返回值输出

  8. Python:元组操作总结

    Python的元组和列表类似,不同之处在于元组中的元素不能修改(因此元组又称为只读列表),且元组使用小括号而列表使用中括号,如下: tup1=('physics','chemistry',1997,2 ...

  9. Android连接SQLServer详细教程(数据库+服务器+客户端)

    摘星 标签: android连接sql http://blog.csdn.net/haoxingfeng/article/details/9111105

  10. mininet实验 动态改变转发规则实验

    写在前面 本实验参考 POX脚本设置好控制器的转发策略,所以只要理解脚本. mininet脚本设置好拓扑和相关信息,所以也只要理解脚本. POX脚本目前基本看不懂. 本实验我学会了:POX控制器Web ...