Time Limit: 10 Sec
Memory Limit: 128 MB
Morenan被困在了一个迷宫里。迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T。可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的有向边,到达另一个点。这样,Morenan走的步数可能很长,也可能是无限,更可能到不了终点。若到不了终点,则步数视为无穷大。但你必须想方设法求出Morenan所走步数的期望值。
第1行4个整数,N,M,S,T
第[2, M+1]行每行两个整数o1, o2,表示有一条从o1到o2的边。
一个浮点数,保留小数点3位,为步数的期望值。若期望值为无穷大,则输出"INF"。
测试点
N M
[1, 6] <=10 <=100
[7, 12] <=200 <=10000
[13, 20] <=10000 <=1000000
保证强连通分量的大小不超过100
设 f [ u ] f[u] f[u]表示 u u u走到 t t t的期望步数
假如在DAG上,则有 f [ u ] = ∑ e d g e ( u , v ) f [ v ] + 1 d e g [ u ] f[u]=\sum_{edge(u,v)}\frac{f[v]+1}{deg[u]} f[u]=∑edge(u,v)deg[u]f[v]+1
但这题是一般图,所以想到对这个式子高斯消元求解
再一看范围emm。。。
注意到有个特殊的提示:“保证强连通分量的大小不超过100”,这启发我们Tarjan求SCC
每个SCC缩点后得到一个DAG
在DAG上按逆拓扑序对每个SCC内的点 u u u用高斯消元求 f [ u ] f[u] f[u]
可以发现每个u出发能到的点v,如果v和u不在同一个SCC内,则 f [ v ] f[v] f[v]已经求得,若在则可用高斯消元求解
由于Tarjan求SCC时得到的标号就是逆拓扑序,所以可以直接按标号顺序推
对于输出INF的情况,若s出发dfs无法到达t,或Tarjan缩点构造DAG之后若发现某个点出度为0且t不在其中,则可判断输出INF
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long lt;
typedef double dd;
#define pb(x) push_back(x)
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxM=2000010;
const int maxN=50010;
int m,s,t;
struct edge{int u,v;}ed[maxM];
struct node{int v,nxt;}E[maxM];
int head[maxN],tot;
int dfn[maxN],low[maxN],cnt;
int st[maxN],top,ins[maxN],col[maxN],coln;
vector<int> scc[maxN];
int vis[maxN],deg[maxN];
int id[maxN],vet[maxN];
dd a[510][510],f[maxN],ans[510];
void add(int u,int v)
{
E[++tot].nxt=head[u];
E[tot].v=v;
head[u]=tot;
}
void tarjan(int u)
{
dfn[u]=low[u]=++cnt;
st[++top]=u; ins[u]=1;
for(int i=head[u];i;i=E[i].nxt)
{
int v=E[i].v;
if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]);}
else if(ins[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
coln++;
do{
int v=st[top];
ins[v]=0; col[v]=coln;
scc[coln].pb(v);
}while(st[top--]!=u);
}
}
void dfs(int u)
{
vis[u]=1;
for(int i=head[u];i;i=E[i].nxt)
if(!vis[E[i].v]) dfs(E[i].v);
}
int check()
{
dfs(s);
if(!vis[t]) return 0;
for(int i=1;i<=m;++i)
if(col[ed[i].u]!=col[ed[i].v])
deg[col[ed[i].u]]++;//出度
for(int i=1;i<=coln;++i)
if(col[t]!=i&&!deg[i]) return 0;
return 1;
}
void matrix(int cor)
{
int sz=scc[cor].size();
for(int i=0;i<sz;++i)
vet[i+1]=scc[cor][i],id[scc[cor][i]]=i+1;
for(int i=1;i<=sz;++i)
a[i][sz+1]=0;
for(int i=1;i<=sz;++i)
for(int j=1;j<=sz;++j)
a[i][j]=(i==j)?1.0:0;
for(int k=1;k<=sz;++k)
{
int u=vet[k];
if(u==t) continue;
for(int i=head[u];i;i=E[i].nxt)
{
int v=E[i].v;
if(col[v]!=cor) a[k][sz+1]+=(f[v]+1)/(dd)(deg[u]);
else a[k][id[v]]-=1.0/(dd)deg[u],a[k][sz+1]+=1.0/(dd)(deg[u]);
}
}
}
void gauss(int col)
{
matrix(col);
int n=scc[col].size();
for(int i=1;i<=n;++i)
{
int r=i;
for(int j=i+1;j<=n;++j)
if(fabs(a[j][i])>fabs(a[r][i])) r=j;
if(r!=i) swap(a[r],a[i]);
dd f=a[i][i];
for(int j=1;j<=n+1;++j) a[i][j]/=f;
for(int j=1;j<=n;++j)
if(i!=j){
f=a[j][i];
for(int k=1;k<=n+1;++k)
a[j][k]-=f*a[i][k];
}
}
for(int i=n;i>=1;--i)
{
ans[i]=a[i][n+1];
for(int j=i+1;j<=n;++j)
ans[i]-=a[i][j]*ans[j];
}
for(int i=1;i<=n;++i)
f[vet[i]]=ans[id[vet[i]]];
}
void solve()
{
memset(deg,0,sizeof(deg));
for(int i=1;i<=m;++i)
deg[ed[i].u]++;
for(int col=1;col<=coln;++col)
gauss(col);
}
int main()
{
int n=read(); m=read();
s=read();t=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
ed[i].u=u; ed[i].v=v;
add(u,v);
}
for(int i=1;i<=n;++i)
if(!dfn[i]) tarjan(i);
if(!check()){ printf("INF"); return 0;}
solve();
printf("%.3lf",f[s]);
return 0;
}