zoukankan      html  css  js  c++  java
  • 【bzoj2707】走迷宫

    Portal --> bzoj2707

    Solution

      首先题目有一个十分明显的暗示。。强联通分量。。那肯定就是要tarjan一波咯

      先看看什么情况下会(INF),其实就是题目里面讲的两种:
      一种是根本走不到出口,一种是存在一个点,起点能够走到这个点但是这个点走不到出口

      具体判断方式的话分别从起点和出口跑两遍dfs就好了

    ​  

      对于不是(INF)的情况,考虑用dp来算到达每个点的期望步数

      用(f[i])表示(i)走到终点的期望步数,(du[i])表示(i)点的出度,对于不为出口的点,可以得到式子

    [f[i]=1+sum f[u]*frac{1}{du[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
    ");return;}
    	++visT;
    	solvedfs(belong[S]);
    	printf("%.3lf
    ",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];
    }
    
  • 相关阅读:
    菜单展开效果
    css3 实现运动动画 圆与椭圆
    css3 翻起页脚
    css3 实现loading效果
    css3
    jquery/原生js/css3 实现瀑布流以及下拉底部加载
    JSON
    js中变量声明提前
    Object.prototype.toString.call(obj)检测数据类型
    call,apply,bind与es6的数组扩展运算符...
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9088141.html
Copyright © 2011-2022 走看看