bzoj 2707: [SDOI2012]走迷宫 (高斯消元+概率期望+tarjan缩点+拓扑序)

2707: [SDOI2012]走迷宫

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 585   Solved: 235
[ 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

round 1 day1

[ Submit][ Status][ Discuss]

题解:高斯消元+概率期望+tarjan缩点+拓扑序

首先感谢zyf2000神犇在我做题的过程中解决我的各种傻逼问题。。。。

对于这道题来说,我们一定要理解清楚题意。题中说的到不了终点不是单纯的说起点和终点不连通,而是说如果有一条路无论如何都到不了终点,那么在走的过程中如果选择了这条路,那么这条路的期望就是INF,对于总的答案来说也是INF。所以我们在缩点之后形成的有向无环图中,如果出度为0的点不只belong[t]或者不是belong[t],那么对于期望步数来书就是INF。

首先进行tarjan缩点,然后按照拓扑序的倒序进行计算。另E[t]=0,然后向前推。

E[x]=(E[v[i]]+1)*p[out[x]] 其中p表示选择走这条边的概率

对于一个强联通分量中的点,建立方程组,然后用高斯消元求解。把强联通分量中的点的E当成未知量,之外的已经求得的点当做常量求解即可。

注意细节,想明白了应该不算太难写。刚开始想的有问题,当时感觉真是难写。

#include
#include
#include
#include
#include
#include
#define N 203
#define M 2000003
#define P 10003
#define eps 1e-9
using namespace std;
double a[N][N],b[N],ans[N],E[P];
int n,m,s,t,out[P],ck[P],vi[P];
int point[M],nxt[M],v[M],tot,dfsn[P],low[P],ins[P],top,sz,cnt,belong[P],st[P];
int head[M],next[M],u[M],mp[P],xk[M],yk[M],du[P];
void guass(int n)
{
	for (int i=1;i<=n;i++) {
		int num=i;
		for (int j=i+1;j<=n;j++)
		 if (fabs(a[j][i])>fabs(a[num][i])) num=j;
		if (num!=i) {
		 for (int j=1;j<=n;j++) swap(a[num][j],a[i][j]);
		 swap(b[num],b[i]);
	    }
	    for (int j=i+1;j<=n;j++) {
	    	if (fabs(a[j][i])=1;i--) {
		double t=1.0*b[i];
		if (fabs(a[i][i])1||num==1&&pos!=belong[t]) {
		printf("INF\n");
		return 0;
	}
	queue p; p.push(pos);
	for (int i=1;i<=n;i++) E[i]=-1;
	while (!p.empty()) {
		int now=p.front(); p.pop();
		T[now].solve();
		for (int i=head[now];i;i=next[i]) {
			du[u[i]]--;
			if (!du[u[i]]) p.push(u[i]);
		}
	}
	if (E[s]==-1||m==0) printf("INF\n"); 
	else printf("%.3lf\n",E[s]);
}


你可能感兴趣的:(图论,高斯消元,概率与期望,tarjan,算法)