首页 > 学院 > 开发设计 > 正文

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

2019-11-06 08:14:47
字体:
来源:转载
供稿:网友

2707: [SDOI2012]走迷宫

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 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 61 21 32 43 54 65 6【样例输出1】3.000【样例输入2】9 12 1 91 22 33 13 43 74 55 66 46 77 88 99 7【样例输出2】9.500【样例输入3】2 0 1 2【样例输出3】INF【数据范围】
测试点NMHint
[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<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<queue>#define N 203#define M 2000003#define P 10003#define eps 1e-9using 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])<eps) continue;	    	double t=a[j][i]/a[i][i];	    	for (int k=1;k<=n;k++)	    	 a[j][k]-=a[i][k]*t;	    	b[j]-=b[i]*t;		}	}	for (int i=n;i>=1;i--) {		double t=1.0*b[i];		if (fabs(a[i][i])<eps) continue;		for (int j=i+1;j<=n;j++) t-=ans[j]*a[i][j];		ans[i]=t/a[i][i];	}}struct data{	int x[103],cnt;	void solve()	{		memset(b,0,sizeof(b));		memset(a,0,sizeof(a));		for (int i=1;i<=cnt;i++) {			if (x[i]==t) {				b[i]=0;				a[i][i]=1;				continue;			}			double p=1.0/out[x[i]];			a[i][i]=1;			for (int j=point[x[i]];j;j=nxt[j]){				if (E[v[j]]!=-1) b[i]+=p*(E[v[j]]+1.0);				else a[i][mp[v[j]]]-=p,b[i]+=p;			}		}		guass(cnt);		for (int i=1;i<=cnt;i++)		 E[x[i]]=ans[i];	}}T[10003];void add(int x,int y){	tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}void tarjan(int x){    ins[x]=1; st[++top]=x; low[x]=dfsn[x]=++sz;    for (int i=point[x];i;i=nxt[i]) {    	int j=v[i];    	if (!dfsn[j]) tarjan(j),low[x]=min(low[x],low[j]);    	else if (ins[j]) low[x]=min(low[x],dfsn[j]);	}	if (low[x]==dfsn[x]) {		++cnt;		int j;		do {			j=st[top--];			belong[j]=cnt;			ins[j]=0;		}while (j!=x);	}}void build(int x,int y){   	tot++; next[tot]=head[x]; head[x]=tot; u[tot]=y;}int main(){	freopen("input.in","r",stdin);	scanf("%d%d%d%d",&n,&m,&s,&t);	for (int i=1;i<=m;i++) {		int x,y; scanf("%d%d",&x,&y);		add(x,y); out[x]++; ins[y]++;	}	for (int i=1;i<=n;i++)	 if (!ins[i]&&!out[i]) ck[i]=1;	memset(ins,0,sizeof(ins));	for (int i=1;i<=n;i++)	 if (!dfsn[i]) tarjan(i);	for (int i=1;i<=n;i++) {		int t=belong[i];		T[t].x[++T[t].cnt]=i;		mp[i]=T[t].cnt;	}	tot=0;	for (int i=1;i<=n;i++) 	 for (int j=point[i];j;j=nxt[j]) {	 	int r1=belong[i]; int r2=belong[v[j]];	 	if (r1!=r2) build(r2,r1),du[r1]++;	 }	for (int i=1;i<=n;i++) 	 if(ck[i]) vi[belong[i]]=1;	int num=0; int pos=0;	for (int i=1;i<=cnt;i++)	 if (du[i]==0&&!vi[i]) num++,pos=i;	if (num>1||num==1&&pos!=belong[t]) {		PRintf("INF/n");		return 0;	}	queue<int> 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]);}


上一篇:Windows编程

下一篇:平分七筐鱼

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表