【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 为了巩固一下刚学习的广搜,练一下迷宫类型的题 不过这道题我用的深搜..... 看问题,我们就知道这道题 ...
随机推荐
- 如何报FOB价格
FOB价格是当货物越过船舷,卖方即完成交货.FOB价格术语仅适用于海运或内河运输.在国际贸易中,FOB价格是比较常用的一种,FOB价格作为众多贸易中的一种需要外贸人员熟悉掌握. FOB价格是当货物越过 ...
- 遗传算法框架GAFT优化小记
前言 前段时间一直在用自己写的遗传算法框架测试算法在优化力场参数的效果,但是跑起来效率很慢,因为适应度函数需要调用多次力场程序计算能量,但是还是比我预想中的慢我也没有及时对程序进行profiling和 ...
- "Hello World!"团队第十次会议
Scrum会议 今天是我们"Hello World!"团队第十次召开会议,博客内容是: 1.会议时间 2.会议成员 3.会议地点 4.会议内容 5.todo list 6.会议照片 ...
- YQCB冲刺周第二天
YQCB冲刺周第二天 1.实现用户记账的功能 2.实现用户头像的设置 3.实现个人设置的功能 遇到的问题: 记账的分类,数据库存取图片,页面跳转+超链接的使用 团队讨论的照片: ...
- 超级迷宫需求分析与建议-NABCD模型
超级迷宫需求分析与建议-NABCD模型 制作者-姜中希 1N-Need 需求 首先这是一个手机游戏风靡的时代,随着智能手机不断的更新问世,4G网络的不断扩大普及,越来越多的手机游戏受到广大玩家的追捧 ...
- dRMT: Disaggregated Programmable Switching
dRMT: Disaggregated Programmable Switching 2017年SIGCOMM会议上提出的新型可编程交换机架构,对2013年提出的RMT架构存在的问题进行了优化. 主要 ...
- android入门 — Activity生命周期
Activity总共有7个回调方法,代表着不同的生命周期的环节. 1.onCreate() 在活动第一次被创建的时候调用.在这个方法中需要完成活动的初始化操作,比如说加载布局.绑定事件等. 2.onS ...
- lintcode-202-线段树的查询
202-线段树的查询 对于一个有n个数的整数数组,在对应的线段树中, 根节点所代表的区间为0-n-1, 每个节点有一个额外的属性max,值为该节点所代表的数组区间start到end内的最大值. 为Se ...
- 倒计时60s 代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- mac下mysql5.7.10密码问题
mysql5.7.10刚安装好,会生成一个随机密码. 如果没记住这个随机密码,那么到mysql/bin/下执行mysql_secure_installation命令 按照提示重置密码和其他选项. ps ...