SDOI2012啊,不错的一道题。
点数很多,我们不能直接高斯消元,而题目中提示了每个强连通分量的点数
<=100
<script type="math/tex" id="MathJax-Element-23"><=100</script>,我们就可以先tarjan缩一下环。
先说一下无解的情况,如果有一个强连通分量到不了
T
,就可以在这个强连通分量内无限的走,答案为
考虑有解的情况,这就成了DAG上的期望DP问题,我们可以用
fi
表示从
i
走到
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 10005
#define M 1000005
using namespace std;
vector<int> V[N];
double f[N],a[105][105];
int n,m,S,T,tot,top,cnt,scc;
int dfn[N],low[N],belong[N],du[N],rank[N],vis[N],stack[N],head[N];
int list[M],next[M];
bool inset[N];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void insert(int x,int y)
{
next[++cnt]=head[x];
head[x]=cnt;
list[cnt]=y;
du[x]++;
}
void tarjan(int x)
{
dfn[x]=low[x]=++tot;
stack[++top]=x;
inset[x]=true;
for (int i=head[x];i;i=next[i])
if (!dfn[list[i]])
{
tarjan(list[i]);
low[x]=min(low[x],low[list[i]]);
}
else if (inset[list[i]]) low[x]=min(low[x],dfn[list[i]]);
if (dfn[x]==low[x])
{
int i=-1;
scc++;
while (i!=x)
{
i=stack[top--];
belong[i]=scc;
rank[i]=V[scc].size();
V[scc].push_back(i);
inset[i]=false;
}
}
}
void dfs(int x)
{
vis[x]=2;
if (x==belong[T])
{
vis[x]=1;
return;
}
for (int i=0;i<V[x].size();i++)
for (int j=head[V[x][i]];j;j=next[j])
if (belong[list[j]]!=x)
{
if (!vis[belong[list[j]]])
dfs(belong[list[j]]);
if (vis[belong[list[j]]]==1)
vis[x]=1;
}
}
void get_ans(int x)
{
int n=V[x].size();
for (int i=0;i<n;i++)
for (int j=head[V[x][i]];j;j=next[j])
if (belong[list[j]]!=x&&!vis[belong[list[j]]])
get_ans(belong[list[j]]);
memset(a,0,sizeof(a));
for (int i=0;i<n;i++)
{
a[i][i]=1;
if (V[x][i]==T) continue;
a[i][V[x].size()]=1;
for (int j=head[V[x][i]];j;j=next[j])
if (belong[list[j]]==x)
a[i][rank[list[j]]]-=1.0/du[V[x][i]];
else a[i][V[x].size()]+=1.0/du[V[x][i]]*f[list[j]];
}
for (int i=0;i<n;i++)
{
double t=a[i][i];
for (int j=0;j<=n;j++)
a[i][j]/=t;
for (int j=0;j<n;j++)
if (j!=i)
{
double t=a[j][i];
for (int k=0;k<=n;k++)
a[j][k]-=t*a[i][k];
}
}
for (int i=0;i<n;i++)
f[V[x][i]]=a[i][n];
vis[x]=1;
}
int main()
{
n=read(); m=read(); S=read(); T=read();
for (int i=1;i<=m;i++)
{
int u=read(),v=read();
insert(u,v);
}
for (int i=1;i<=n;i++)
if (!dfn[i]) tarjan(i);
memset(vis,0,sizeof(vis));
dfs(belong[S]);
for (int i=1;i<=scc;i++)
if (vis[i]==2)
{
puts("INF");
return 0;
}
memset(vis,0,sizeof(vis));
get_ans(belong[S]);
printf("%.3lf\n",f[S]);
return 0;
}