BZOJ2707 [SDOI2012]走迷宫

84 篇文章 1 订阅
8 篇文章 0 订阅

设f[i]表示从第i个点走到终点的期望,d[i]表示i的出度,j是第i个点能走到的点

则f[i]=sigma (f[j]+1)/d[i]

在数据范围小的情况下,我们可以高斯消元求出f数组

由于本题中每个边双大小<=100,把边双缩点之后的图是有拓扑序的,所以我们可以按拓扑序求,每个边双内高斯消元

不过这复杂度上限不是100^4的么……反正能过……

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
#include<vector>
#include<set>
using namespace std;
#define MAXN 10010
#define MAXM 1000010
#define INF 1000000000
#define MOD 1000000007
#define ll long long
#define eps 1e-8
struct vec{
	int to;
	int fro;
};
struct G{
	vec mp[MAXM];
	int tai[MAXN],cnt;
	inline void be(int x,int y){
		mp[++cnt].to=y;
		mp[cnt].fro=tai[x];
		tai[x]=cnt;
	}
	void dfs(int x);
	void build();
	void cal(int x);
	void get(int x);
};
G g,ng;
bool ist[MAXN];
int st[MAXN],tp;
int dfn[MAXN],ndf[MAXN],low[MAXN],tim;
int bel[MAXN],siz[MAXN],tot;
int n,m;
vector<int>ps[MAXN];
bool vis[MAXN],VIS[MAXN];
double f[MAXN];
int d[MAXN];
int S,T;
int lst[110][110];
double a[110][110];
void G::dfs(int x){
	int i,y;
	dfn[x]=low[x]=++tim;
	ist[st[++tp]=x]=1;
	for(i=tai[x];i;i=mp[i].fro){
		y=mp[i].to;
		if(!dfn[y]){
			dfs(y);
			low[x]=min(low[x],low[y]);
		}else if(ist[y]){
			low[x]=min(low[x],dfn[y]);
		}
	}
	if(low[x]==dfn[x]){
		int t=0;
		tot++;
		while(t!=x){
			ist[t=st[tp--]]=0;
			siz[bel[t]=tot]++;
			ps[tot].push_back(t);
		}
	}
}
void G::build(){
	int i,x,y;
	for(x=1;x<=n;x++){
		for(i=tai[x];i;i=mp[i].fro){
			y=mp[i].to;
			if(bel[x]!=bel[y]){
				ng.be(bel[x],bel[y]);
			}
		}
	}
}
void jud(int x,int y){
	if(lst[x][y]!=tim){
		a[x][y]=0;
	}
	lst[x][y]=tim;
}
void G::get(int x){
	int i,y;
	for(i=tai[x];i;i=mp[i].fro){
		y=mp[i].to;
		if(VIS[y]){
			jud(dfn[x],tot+1);
			a[dfn[x]][tot+1]+=1.0*(f[y]+1)/d[x];
		}else{
			jud(dfn[x],dfn[y]);
			jud(dfn[x],tot+1);
			a[dfn[x]][tot+1]+=1.0/d[x];
			a[dfn[x]][dfn[y]]-=1.0/d[x];
		}
	}
}
void gs(){
	int i,j,k;
	for(i=1;i<=tot;i++){ 
		jud(i,i);
		if(fabs(a[i][i])<eps){
			for(j=i+1;j<=tot;j++){
				jud(j,i);
				if(fabs(a[j][i]>eps)){
					for(k=1;k<=tot+1;k++){
						jud(i,k);
						jud(j,k);
						swap(a[i][k],a[j][k]);
					}
				}
			}
		}
		if(fabs(a[i][i]>eps)){
			for(j=1;j<=tot;j++){
				if(i!=j){
					jud(j,i);
					double t=a[j][i]/a[i][i];
					for(k=1;k<=tot+1;k++){
						jud(i,k);
						jud(j,k);
						a[j][k]-=t*a[i][k];
					}
				}
			}
		}
	}
}
void G::cal(int x){
	int i,y;
	if(vis[x]){
		return ;
	}
	vis[x]=1;
	for(i=tai[x];i;i=mp[i].fro){
		cal(mp[i].to);
	}
	tot=0;
	tim++;
	for(i=0;i<ps[x].size();i++){
		ndf[++tot]=ps[x][i];
		dfn[ps[x][i]]=tot;
		jud(tot,tot);
		a[tot][tot]=1;
	}
	for(i=0;i<ps[x].size();i++){
		g.get(ps[x][i]);
	}
	gs();
	for(i=1;i<=tot;i++){
		jud(i,i);
		if(fabs(a[i][i])<eps){
			printf("INF\n");
			exit(0);
		}
		f[ndf[i]]=a[i][tot+1]/a[i][i];
		VIS[ndf[i]]=1;
	}
	
}
int main(){
	int i,x,y;
	scanf("%d%d%d%d",&n,&m,&S,&T);
	for(i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		if(x!=T){
			g.be(x,y);
			d[x]++;
		}
	}
	g.dfs(S);
	for(i=1;i<=n;i++){
		if(i!=T){
			if(dfn[i]&&(!d[i])){
				printf("INF\n");
				return 0;
			}
		}else{
			if(!dfn[i]){
				printf("INF\n");
				return 0;
			}
		}
	}
	g.build();
	vis[bel[T]]=1;
	VIS[T]=1;
	ng.cal(bel[S]);
	printf("%.3lf\n",f[S]);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

/*

*/


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值