BZOJ2707: [SDOI2012]走迷宫
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2707
首先找出所有强联通分量然后缩点,然后从开始点的那个联通块开始dfs,如果发现它走到了死路,那么期望步数就是无限大。
然后判断掉无限大的情况后我们对每个scc求期望,对于scc中的每个点,由E[u]=ΣE[v]*1/d[u]+1,联立方程高斯消元。(如果连边连到scc外,就让常数项加上E[x]/d[u])
注意E[t]=0,然后要把t的所有出边全部砍掉。但是建方程的时候其系数还要是1。。。
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<stack> #include<cstring> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxm 1005000 #define maxn 105000 #define eps 1e-6 using namespace std; stack<int >q; struct data{int obj,pre; }e[maxm]; int head[maxn],low[maxn],dfn[maxn],vis[maxn],num[maxn],d[maxn],size[maxn],rank[maxn],cal[maxn]; int b[maxn][205]; double a[205][205],ex[maxn]; int idx,tot,scc,n,m,s,t; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } void insert(int x,int y){ e[++tot].obj=y; e[tot].pre=head[x]; head[x]=tot; } void tarjan(int u){ dfn[u]=low[u]=++idx; q.push(u); for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if (!num[v]) low[u]=min(low[u],dfn[v]); } if (low[u]==dfn[u]){ int x=-1,cnt=0; ++scc; while (x!=u){ x=q.top(); q.pop(); num[x]=scc; rank[x]=++cnt; size[scc]++; b[scc][size[scc]]=x; } } } void dfs(int x){ vis[x]=0; if (x==num[t]){ vis[x]=1; return ; } rep(i,1,size[x]){ int u=b[x][i]; for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (num[v]==x) continue; if (vis[num[v]]==-1) dfs(num[v]); if (vis[num[v]]==1) vis[x]=1; } } } void gs(int n){ int x; rep(i,1,n){ x=i; while (fabs(a[x][i])<eps&&x<=n) x++; if (x>n) continue; rep(j,1,n+1) swap(a[i][j],a[x][j]); double t=a[i][i]; rep(j,1,n+1) a[i][j]/=t; rep(j,1,n) if (j!=i){ double t=a[j][i]; rep(k,1,n+1) a[j][k]-=t*a[i][k]; } } } void solve(int x){ rep(i,1,size[x]){ int u=b[x][i]; for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (num[v]!=x&&!cal[num[v]]) solve(num[v]); } } clr(a,0); rep(i,1,size[x]){ a[i][i]=1.0; int u=b[x][i]; if (u==t) continue; a[i][size[x]+1]=1.0; for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (num[v]==x) a[i][rank[v]]-=1.0/d[u]; else a[i][size[x]+1]+=1.0/d[u]*ex[v]; } } gs(size[x]); rep(i,1,size[x]) ex[b[x][i]]=a[rank[b[x][i]]][size[x]+1]; cal[x]=1; } int main(){ n=read(); m=read(); s=read(); t=read(); if (s==t){ puts("0.000"); return 0; } rep(i,1,m){ int x,y; x=read(); y=read(); insert(x,y); d[x]++; } rep(i,1,n){ if (!dfn[i]) tarjan(i); } clr(vis,-1); dfs(num[s]); rep(i,1,scc) if (vis[i]==0) { puts("INF"); return 0; } solve(num[s]); printf("%.3lf\n",ex[s]); return 0; }