【bzoj2707】走迷宫
Solution
首先题目有一个十分明显的暗示。。强联通分量。。那肯定就是要tarjan一波咯
先看看什么情况下会\(INF\),其实就是题目里面讲的两种:
一种是根本走不到出口,一种是存在一个点,起点能够走到这个点但是这个点走不到出口
具体判断方式的话分别从起点和出口跑两遍dfs就好了
对于不是\(INF\)的情况,考虑用dp来算到达每个点的期望步数
用\(f[i]\)表示\(i\)走到终点的期望步数,\(du[i]\)表示\(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】走迷宫的更多相关文章
- [BZOJ2707]走迷宫
Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿 ...
- 【BZOJ2707】[SDOI2012]走迷宫 Tarjan+拓扑排序+高斯消元+期望
[BZOJ2707][SDOI2012]走迷宫 Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,M ...
- C语言动态走迷宫
曾经用C语言做过的动态走迷宫程序,先分享代码如下: 代码如下: //头文件 #include<stdio.h> #include<windows.h>//Sleep(500)函 ...
- sdut 2449走迷宫【最简单的dfs应用】
走迷宫 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_ 题目描述 一个由n * m 个格子组成的迷宫,起点是(1, 1), 终点是(n, m) ...
- 洛谷P1238 走迷宫
洛谷1238 走迷宫 题目描述 有一个m*n格的迷宫(表示有m行.n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这m*n个数据和起始点.结束点(起始点和结束点都是用两个 ...
- BZOJ 2707: [SDOI2012]走迷宫( tarjan + 高斯消元 )
数据范围太大不能直接高斯消元, tarjan缩点然后按拓扑逆序对每个强连通分量高斯消元就可以了. E(u) = 1 + Σ E(v) / degree(u) 对拍时发现网上2个程序的INF判断和我不一 ...
- NYOJ306 走迷宫(dfs+二分搜索)
题目描写叙述 http://acm.nyist.net/JudgeOnline/problem.php?pid=306 Dr.Kong设计的机器人卡多非常爱玩.它经常偷偷跑出实验室,在某个游乐场玩之不 ...
- Problem A: 走迷宫问题
Problem A: 走迷宫问题Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 9 Solved: 3[Submit][Status][Web Board] ...
- BZOJ 2707: [SDOI2012]走迷宫 [高斯消元 scc缩点]
2707: [SDOI2012]走迷宫 题意:求s走到t期望步数,\(n \le 10^4\),保证\(|SCC| \le 100\) 求scc缩点,每个scc高斯消元,scc之间直接DP 注意每次清 ...
- P1238 走迷宫
原题链接 https://www.luogu.org/problemnew/show/P1238 为了巩固一下刚学习的广搜,练一下迷宫类型的题 不过这道题我用的深搜..... 看问题,我们就知道这道题 ...
随机推荐
- gtest命令行测试案例
使用gtest编写的测试案例通常本身就是一个可执行文件,因此运行起来非常方便.同时,gtest也为我们提供了一系列的运行参数(环境变量.命令行参数或代码里指定),使得我们可以对案例的执行进行一些有效的 ...
- 【转】lvs、nginx、haproxy转发模式优缺点总结
原文地址: https://yq.aliyun.com/ziliao/78374 一.LVS转发模式 LVS是章文嵩博士写的一个工作于四层的高可能性软件.不像后两者支持七层转发,不过也正因为其简单,所 ...
- 微软职位内部推荐-Senior Software Engineer II-Sharepoint
微软近期Open的职位: SharePoint is a multi-billion dollar enterprise business that has grown from an on-prem ...
- 用 Python 编写的 Python 解释器
Allison是Dropbox的工程师,在那里她维护着世界上最大的由Python客户组成的网络.在Dropbox之前,她是Recurse Center的引导师, … 她在北美的PyCon做过关于Pyt ...
- 通过Nrgok映射外网调试微信
一.注册账号 注册地址:http://www.ngrok.cc/login 登录系统,新增域名 二.下载客户端,修改配置文件 修改ngrok.cfg auth_token值登录平台管理系统可查看 su ...
- Beta发布—美工+文案
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2408 视频展示地址:https://www.bilibili.com/v ...
- Python学习之路8 - 内置方法
abs(-230) #取绝对值 all([0,1,-5]) #如果参数里面的所有值都为真就返回真,否则返回假 any([0,1,-5]) #如果参数里面有一个值为真则返回真,否则返回假 ascii([ ...
- .net组件和com组件&托管代码和非托管代码
com组件和.net组件: COM组件是非托管对象,可以不需要.NET框架而直接运行,.NET框架组件是托管对象,必须有.NET框架的支撑才能运行. COM组件有独立的类型库文件,而.NET组件是通过 ...
- C++:const用法的简单总结
一.对变量的修饰 在c++中,如果我们希望定义一个值不会被改变的变量,那么可以用关键字const对它进行修饰,被修饰后的变量其作用相当于一个常量 //这两种方式等价 2 语法1:const 类型名 变 ...
- c艹第三次作业
1.git地址,不要介意仓库名. https://github.com/b666666666666666b/elevator-schedualing 2.首先,我先说一下我是怎么实现三个电梯的. 首先 ...