╰( ̄▽ ̄)╭
Morenan 被困在了一个迷宫里。
迷宫可以视为 N 个点 M 条边的有向图,其中 Morena n处于起点 S , 迷宫的终点设为 T 。
可惜的是 , Morenan 非常的脑小 , 他只会从一个点出发随机沿着一条从该点出发的有向边 , 到达另一个点 。
这样 , Morenan 走的步数可能很长 , 也可能是无限,更可能到不了终点。
若到不了终点,则步数视为无穷大。
但你必须想方设法求出 Morenan 所走步数的期望值。
(⊙ ▽ ⊙)
一开始看着道题,就觉得是tarjan缩点后,转化成DAG上的问题。
当原图是DAG时
设
容易有
其中
很容易使用拓扑排序来完成动态规划。
当原图是一般的有向图时
利用
对于任意一个强连通分量,我们利用高斯消元来求解出强连通分量中的每个点的
套上拓扑排序,就能够解决。
时间复杂度为
实际时间复杂度则远远不到。
( ̄~ ̄)
高斯(gauss)消元:
1.目标
对
2.步骤
首先:
把某条方程的第一个元的系数化为一,利用它可以消去其他方程的第一元。
以此类推,可以消去第二个元、第三个元……
最后,会只剩下一条只关于最后一元的方程,实际上就是这一元的根。
然后:
得出最后一元的根后,就可以代入先前的方程。
于是可以算出所有元的根。
(⊙v⊙)
#include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<math.h> #define ll long long using namespace std; const char* fin="jzoj2758.in"; const char* fout="jzoj2758.out"; const int Inf=0x7fffffff; const int maxn=20007,maxm=2000007,maxk=107; int n,m,St,En,i,j,k,N,ti; int fi[maxn],ne[maxm],la[maxm],tot; int Fi[maxn],Ne[maxm],La[maxm],Tot; int dfn[maxn],low[maxn],num,st[maxn],be[maxn]; bool bz[maxn],End; int inf[maxn]; int az[maxn]; int ha[maxn][maxk],ru[maxn],id[maxn],tow[maxn]; double f[maxn],gs[maxk][maxk]; int b[maxn],head,tail; void add_line(int a,int b){ tot++; ne[tot]=fi[a]; la[tot]=b; fi[a]=tot; } void Add_line(int a,int b){ Tot++; Ne[Tot]=Fi[a]; La[Tot]=b; Fi[a]=Tot; } void tarjan(int v){ int i,j,k; dfn[v]=low[v]=++num; bz[st[j=++st[0]]=v]=true; for (k=fi[v];k;k=ne[k]) if (!dfn[la[k]]){ tarjan(la[k]); low[v]=min(low[v],low[la[k]]); }else if (bz[la[k]]) low[v]=min(low[la[k]],low[v]); if (low[v]==dfn[v]){ N++; be[N]=0; while (st[0]>=j){ ha[N][++ha[N][0]]=st[st[0]]; be[st[st[0]]]=N; bz[st[st[0]--]]=false; } } } double ABS(double x){ return x>0?x:-x; } void add(int v){ b[++tail]=v; } void count(int v,int n){ int i,j,k,l; double tmp,tmd; ti++; for (i=1;i<=n-1;i++){ for (j=1;j<n;j++){ if (az[j]<ti && (gs[j][i]>10e-13 || gs[j][i]<-10e-13)){ az[j]=ti; tow[i]=j; tmp=1.0/gs[j][i]; for (k=1;k<=n;k++) gs[j][k]*=tmp; for (k=1;k<n;k++){ if (k==j) continue; tmd=gs[k][i]; for (l=1;l<=n;l++) gs[k][l]-=tmd*gs[j][l]; } break; } } } for (i=n-1;i>=1;i--){ f[ha[v][tow[i]]]=-gs[tow[i]][n]; for (j=1;j<=n-1;j++){ gs[j][n]-=gs[j][i]*gs[tow[i]][n]; } } } void work(int v){ int i,j,k; for (i=1;i<=ha[v][0];i++) id[ha[v][i]]=i; for (i=1;i<=ha[v][0];i++){ for (j=1;j<=ha[v][0]+1;j++) gs[i][j]=0; j=0; for (k=Fi[ha[v][i]];k;k=Ne[k]){ gs[i][ha[v][0]+1]+=1; gs[i][i]-=1; if (f[La[k]]>10e-7 || La[k]==En) gs[i][ha[v][0]+1]+=f[La[k]]; else gs[i][id[La[k]]]+=1; } } count(v,ha[v][0]+1); } void update(int v){ int i,j,k; for (i=1;i<=ha[v][0];i++) for (k=fi[ha[v][i]];k;k=ne[k]){ inf[be[la[k]]]=max(inf[be[la[k]]],inf[v]); if (!--ru[be[la[k]]]) add(be[la[k]]); } } void topsort(){ int i,j,k; head=tail=0; memset(f,0,sizeof(f)); f[En]=0; for (i=n+1;i<=N;i++) if (!ru[i]){ add(i); } while (head++<tail){ if (be[En]==b[head]) inf[b[head]]=1; if (inf[b[head]]==0) inf[b[head]]=2; if (inf[b[head]]==1 && b[head]!=be[En]) work(b[head]); update(b[head]); } } int main(){ scanf("%d%d%d%d",&n,&m,&St,&En); N=n; for (i=1;i<=m;i++){ scanf("%d%d",&j,&k); if (j!=En){ Add_line(j,k); add_line(k,j); } } for (i=1;i<=n;i++) if (!dfn[i]) tarjan(i); for (i=1;i<=n;i++) for (k=fi[i];k;k=ne[k]) if (be[la[k]]!=be[i]) ru[be[la[k]]]++; topsort(); //printf("%3.lf",f[St]); if (inf[be[St]]!=1) printf("INF"); else printf("%.3lf",f[St]); return 0; }
来源:https://www.cnblogs.com/hiweibolu/p/6714797.html