数据范围太大不能直接高斯消元, tarjan缩点然后按拓扑逆序对每个强连通分量高斯消元就可以了.

E(u) = 1 + Σ E(v) / degree(u)

对拍时发现网上2个程序的INF判断和我不一样(他们2个的INF判断也不一样).....然而都A掉了....我觉得应该是他们写错了,我的做法应该没错的(正反2遍dfs,GDOI2015day1t1大冒险)(求打脸

------------------------------------------------------------------------

#include<cmath>
#include<stack>
#include<cstdio>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
const int maxn = 10009;
const int maxb = 209;
const double eps = 1e-8;
 
int N, S, T, deg[maxn];
int dfn[maxn], low[maxn], sz[maxn], CK;
int scc[maxn], Scc[maxn][maxb], Id[maxn], n;
bool F[maxn];
stack<int> stk;
double ans[maxn], mat[maxb][maxb];
 
inline void Min(int &x, int t) {
if(t < x) x = t;
}
 
struct edge {
int t;
edge* n;
} E[5000000], *pt = E;
 
struct G {
edge* H[maxn];
bool vis[maxn];
inline void AddEdge(int u, int v) {
pt->t = v, pt->n = H[u], H[u] = pt++;
}
void dfs(int x) {
vis[x] = true;
for(edge* e = H[x]; e; e = e->n)
if(!vis[e->t]) dfs(e->t);
}
void DFS(int x) {
memset(vis, 0, sizeof vis);
dfs(x);
}
} g[3];
 
void tarjan(int x) {
dfn[x] = low[x] = ++CK;
stk.push(x);
for(edge* e = g[0].H[x]; e; e = e->n) if(!dfn[e->t]) {
tarjan(e->t);
Min(low[x], low[e->t]);
} else if(!~scc[e->t])
Min(low[x], dfn[e->t]);
if(dfn[x] == low[x]) {
int t;
do {
t = stk.top(); stk.pop();
scc[t] = n;
Id[t] = sz[n];
Scc[n][sz[n]++] = t;
} while(t != x);
n++;
}
}
 
void Init() {
int m, u, v;
scanf("%d%d%d%d", &N, &m, &S, &T);
S--, T--;
memset(deg, 0, sizeof deg);
while(m--) {
scanf("%d%d", &u, &v);
u--, v--;
if(u == T) continue;
g[0].AddEdge(u, v);
deg[u]++;
}
}
 
void Solve(int x) {
if(x == scc[T]) {
ans[T] = 0;
return;
}
for(int i = 0; i < sz[x]; i++) {
for(int j = 0; j < sz[x]; j++) mat[i][j] = 0;
mat[i][sz[x]] = deg[Scc[x][i]];
for(edge* e = g[0].H[Scc[x][i]]; e; e = e->n)
if(scc[e->t] == x) {
mat[i][Id[e->t]]--;
} else if(e->t != T)
mat[i][sz[x]] += ans[e->t];
mat[i][i] += deg[Scc[x][i]];
}
for(int i = 0, r; i < sz[x]; i++) {
r = i;
for(int j = i; ++j < sz[x]; )
if(fabs(mat[j][i]) > fabs(mat[r][i])) r = j;
if(r != i) {
for(int j = 0; j <= sz[x]; j++)
swap(mat[i][j], mat[r][j]);
}
for(int j = i; ++j < sz[x]; ) {
double t = mat[j][i] / mat[i][i];
for(int k = i; k <= sz[x]; k++)
mat[j][k] -= t * mat[i][k];
}
}
for(int i = sz[x]; i--; ) {
for(int j = i; ++j < sz[x]; )
mat[i][sz[x]] -= mat[j][sz[x]] * mat[i][j];
mat[i][sz[x]] /= mat[i][i];
}
for(int i = 0; i < sz[x]; i++)
ans[Scc[x][i]] = mat[i][sz[x]];
}
 
void dfs(int x) {
for(edge* e = g[1].H[x]; e; e = e->n)
if(!F[e->t]) dfs(e->t);
F[x] = true;
Solve(x);
}
 
void Work() {
if(S == T) {
puts("0.000");
return;
}
memset(dfn, 0, sizeof dfn);
memset(scc, -1, sizeof scc);
memset(sz, 0, sizeof sz);
CK = n = 0;
for(int i = 0; i < N; i++)
if(!dfn[i]) tarjan(i);
for(int i = 0; i < N; i++)
for(edge* e = g[0].H[i]; e; e = e->n) if(scc[i] != scc[e->t]) {
g[1].AddEdge(scc[i], scc[e->t]);
g[2].AddEdge(scc[e->t], scc[i]);
}
g[1].DFS(scc[S]), g[2].DFS(scc[T]);
for(int i = 0; i < n; i++) if(g[1].vis[i] && !g[2].vis[i]) {
puts("INF"); return;
}
memset(F, 0, sizeof F);
dfs(scc[S]);
printf("%.3lf\n", ans[S]);
}
 
int main() {
Init();
Work();
return 0;
}

------------------------------------------------------------------------

2707: [SDOI2012]走迷宫

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 372  Solved: 149
[Submit][Status][Discuss]

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"。
【样例输入1】
6 6 1 6
1 2
1 3
2 4
3 5
4 6
5 6
【样例输出1】
3.000
【样例输入2】
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
【样例输出2】
9.500
【样例输入3】
2 0 1 2
【样例输出3】
INF
【数据范围】
测试点
N
M
Hint
[1, 6]
<=10
<=100
 
[7, 12]
<=200
<=10000
 
[13, 20]
<=10000
<=1000000
保证强连通分量的大小不超过100
 
 
另外,均匀分布着40%的数据,图中没有环,也没有自环

Sample Input

Sample Output

HINT

Source

BZOJ 2707: [SDOI2012]走迷宫( tarjan + 高斯消元 )的更多相关文章

  1. BZOJ 2707: [SDOI2012]走迷宫 拓扑+高斯消元+期望概率dp+Tarjan

    先Tarjan缩点 强连通分量里用高斯消元外面直接转移 注意删掉终点出边和拓扑 #include<cstdio> #include<cstring> #include<a ...

  2. 洛谷 P6030 - [SDOI2012]走迷宫(高斯消元+SCC 缩点)

    题面传送门 之所以写个题解是因为题解区大部分题解的做法都有 bug(u1s1 周六上午在讨论区里连发两个 hack 的是我,由于我被禁言才让 ycx 代发的) 首先碰到这种期望题,我们套路地设 \(d ...

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

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

  4. BZOJ.2707.[SDOI2012]走迷宫(期望 Tarjan 高斯消元)

    题目链接 一个点到达终点的期望步数 \(E_i=\sum_{(i,j)\in G}\frac{E_j+1}{out[i]}\),\(out[i]\)为点\(i\)的出度. 那么对于一个DAG可以直接在 ...

  5. bzoj 2707 [SDOI2012]走迷宫(SCC+高斯消元)

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

  6. bzoj千题计划289:bzoj 2707: [SDOI2012]走迷宫

    http://www.lydsy.com/JudgeOnline/problem.php?id=2707 dp[i] 表示从点i到终点的期望步数 dp[i]= Σ (dp[j]+1)/out[i] j ...

  7. BZOJ 3143 游走(贪心+期望+高斯消元)

    一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分 ...

  8. BZOJ 3143 游走 | 数学期望 高斯消元

    啊 我永远喜欢期望题 BZOJ 3143 游走 题意 有一个n个点m条边的无向联通图,每条边按1~m编号,从1号点出发,每次随机选择与当前点相连的一条边,走到这条边的另一个端点,一旦走到n号节点就停下 ...

  9. BZOJ.4820.[SDOI2017]硬币游戏(思路 高斯消元 哈希/AC自动机/KMP)

    BZOJ 洛谷 建出AC自动机,每个点向两个儿子连边,可以得到一张有向图.参照 [SDOI2012]走迷宫 可以得到一个\(Tarjan\)+高斯消元的\(O((nm)^3)\)的做法.(理论有\(6 ...

随机推荐

  1. Mobile Web开发 处理设备的横竖屏

    为了应对移动设备屏幕的碎片化,我们在开发Mobile Web应用时,一个最佳实践就是采用流式布局,保证最大可能地利用有限的屏幕空间.由于屏幕存在着方向性,用户在切换了屏幕的方向后,有些设计上或实现上的 ...

  2. ZCTF-final-restaurant1

    和线上赛的题目差别不大,但是需要自己去泄露堆的地址.除了线上赛的溢出之外,还多了一个Use After Free的洞.我写了两种利用方法. 线上赛writeup见:http://www.cnblogs ...

  3. 通过设置cookie实现单点登录

    最近要做个登录一个客户端跳转到另一个网站不用再登录,有两种方法,第一种就是写接口通过客户端传值账号直接到目标网站,另一种是写入cookie到目标网站.由于目标网站之前就是通过cookie实现单点登录, ...

  4. 关于sql 外键的讨论。

    外键是否采用看业务应用场景,以及开发成本的,大致列下什么时候适合,什么时候不适合使用: 1. 互联网行业应用不推荐使用外键: 用户量大,并发度高,为此数据库服务器很容易成为性能瓶颈,尤其受IO能力限制 ...

  5. [方法]本来好的中文在winEdt中打开变成乱码

    场景:本来在winEdt中使用中文的tex文件,使用xelatex可以编译成pdf,今天打开该tex文件,所有中文变得不可读,统统乱码. 解决方法:在保存tex文件时使用的是utf-8保存的,所以在打 ...

  6. delphi 对TThread扩充TSimpleThread

    对线程的使用,是每个开发者都应该熟练掌握的,也是进阶的重要一环. 可以这样说,没有线程,连界面假死的问题都解决不了,就更别谈并行处理来提高效率了. 本例对线程进行改进,打造一个基础的线程,以后线程应用 ...

  7. C++临时对象销毁时间

    下面这段代码会输出什么? const char* p = string("hello temprary string").c_str(); cout << p; 下面这 ...

  8. C语言入门(21)——使用DBG对C语言进行调试

    C语言入门(21)--使用DBG对C语言进行调试 程序中除了一目了然的Bug之外都需要一定的调试手段来分析到底错在哪.到目前为止我们的调试手段只有一种:根据程序执行时的出错现象假设错误原因,然后在代码 ...

  9. omnibus方式部署gitlab

    omnibus方式部署gitlab Posted on 2015 年 1 月 10 日   4233 Views 这几天折腾搭建git服务器,选择了比较流行的gitlab,一开始就直奔一键安装脚本去了 ...

  10. 如何同时激活两个不同版本的MyEclipse 【MyEclipse2013和MyEclipse2014同时激活】

    激活一个MyEclipse的步骤,大家都会,在这里就不多说了,不会的可以看:http://jingyan.baidu.com/article/3ea51489cc14d452e71bba7a.html ...