当前位置: 代码迷 >> 综合 >> [bzoj2707][SDOI2012]走迷宫(tarjan+拓扑排序+高斯消元)
  详细解决方案

[bzoj2707][SDOI2012]走迷宫(tarjan+拓扑排序+高斯消元)

热度:53   发布时间:2024-02-09 01:16:34.0

先tarjan求出强连通分量,然后按拓扑倒序做,对于每个强连通分量内用高斯消元求出期望。这样一个点的期望就等于1/出度*Σ(所指向点的期望) +1。自环不忽略,重边不忽略。对于期望了解不多的我一开始没太想清楚。

然后如果从起点能走到一个没有出度且不包含终点的分量,那就是无解,所以拓扑倒序的话就是如果一个这样的分量能指到起点所在分量,就是无解。

程序写的比较笨拙,设私密吧。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=10010,M=1000010,NN=105;
struct edge{int y,next;
}data[M],data1[M];
double mt[NN][NN],dp[N];
int n,m,s,t,num,num1;
queue<int> q;
int in[N],h[N],h1[N],dfn[N],low[N],sta[N],top,numm,insta[N],vis[N],f[N],lst[N][NN],tid[N],fail[N];
inline int read(){int x=0,f=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return f?-x:x;
}
inline void addedge(int x,int y){data[++num].y=y,data[num].next=h[x],h[x]=num;
}
inline void addedge1(int x,int y){data1[++num1].y=y,data1[num1].next=h1[x],h1[x]=num1;
}
inline int min1(int x,int y){return x<y?x:y;
}
inline void gauss(int c,int tot){vis[c]=1;memset(mt,0,sizeof mt);if(f[t]==c){for(int cnt,i=1;i<=tot;++i){if(tid[t]==i)continue;double w=0;cnt=0;for(int j=h[lst[c][i]];j!=-1;j=data[j].next){int v=data[j].y;if(f[v]!=c){if(vis[f[v]])w-=dp[v],++cnt;continue;}mt[i][tid[v]]+=1,++cnt;}mt[i][tot+1]=w-1.0*cnt,mt[i][i]+=-1.0*cnt;}mt[tid[t]][tid[t]]=1,mt[tid[t]][tot+1]=0;}else{for(int cnt,i=1;i<=tot;++i){double w=0;cnt=0;for(int j=h[lst[c][i]];j!=-1;j=data[j].next){int v=data[j].y;if(f[v]!=c){if(vis[f[v]])w-=dp[v],++cnt;continue;}mt[i][tid[v]]+=1,++cnt;}mt[i][tot+1]=w-1.0*cnt,mt[i][i]+=-1.0*cnt;}}for(int i=1;i<=tot;++i){for(int j=i+1;j<=tot+1;++j)mt[i][j]/=mt[i][i];mt[i][i]=1;for(int j=1;j<=tot;++j){if(i==j)continue;double x=mt[j][i];for(int k=1;k<=tot+1;++k)mt[j][k]-=x*mt[i][k];}}for(int i=1;i<=tot;++i)dp[lst[c][i]]=mt[i][tot+1];
}
void tarjan(int u){dfn[u]=low[u]=++numm,vis[u]=insta[u]=1;sta[++top]=u;for(int i=h[u];i!=-1;i=data[i].next){int v=data[i].y;if(!vis[v]){tarjan(v);low[u]=min1(low[u],low[v]);}else if(insta[v]&&dfn[v]<low[u])low[u]=dfn[v];}if(dfn[u]==low[u]){int cnt=0;while(dfn[sta[top]]!=low[sta[top]])f[sta[top]]=u,lst[u][++cnt]=sta[top],tid[sta[top]]=cnt,insta[sta[top--]]=0;f[u]=u,lst[u][++cnt]=u,tid[u]=cnt,insta[sta[top--]]=0,lst[u][0]=cnt;}
}
int main(){n=read(),m=read(),s=read(),t=read();memset(h,-1,sizeof h),num=0;for(int u,v,i=1;i<=m;++i)u=read(),v=read(),addedge(u,v);memset(vis,0,sizeof vis),numm=0;for(int i=1;i<=n;++i)if(!vis[i])tarjan(i);memset(h1,-1,sizeof h1),num1=0,memset(in,0,sizeof in);for(int i=1;i<=n;++i)for(int j=h[i];j!=-1;j=data[j].next){int v=data[j].y;if(f[v]!=f[i])addedge1(f[v],f[i]),++in[f[i]];}while(!q.empty())q.pop();memset(fail,0,sizeof fail);memset(dp,0,sizeof dp);for(int i=1;i<=n;++i)if(!in[i]){if(i!=f[t])fail[i]=1;q.push(i);}while(!q.empty()){int u=q.front();q.pop();if(!fail[u])gauss(u,lst[u][0]);for(int i=h1[u];i!=-1;i=data1[i].next){int v=data1[i].y;--in[v];if(fail[u])fail[v]=1;if(!in[v])q.push(v);}}if(fail[f[s]]){printf("INF");return 0;}printf("%.3lf",dp[s]);return 0;
}