[gym101981F]Frank
在本题中,每一步是独立的,因此即可以看作从s移动到t的期望步数(对于每一对s和t都求出答案)
令fi,j表示当s=i且t=j时的答案,则有fi,j={∑(i,k)∈nw(i,k)fk,j+1(i≠j)0(i=j)
事实上,对于每一个j,其仅有在i=j时的方程不同,我们需要利用这个公共部分
更具体的,令gi=∑(i,j)∈nw(i,j)fj,i+1,即s=t=i且强制第一次不能结束的期望步数
将其简单变形,即有fi,i=∑(i,j)∈nw(i,j)fj,i+1−gi,i=0(即恰好为0)
构造矩阵Mi,j=w(i,j),Fi,j=fi,j,Gi,j={gi(i=j)0(i≠j)以及全1矩阵Ji,j=1,那么根据前面的递推式,就可以得到MF+J−G=F
进而,即(M−I)F=G−J,问题即变为求G以及G−JM−I
G的计算
再构造一个1×|V|的矩阵π,满足∑|V|i=1π1,i=1且πM=π
结论5:∀1≤i≤n,giπ1,i=1
考虑条件MF+J−G=F,两边同时左乘π即πMF+πJ−πG=πF
注意到πM=π,化简后即有πJ=πG
由此,即(πG)i=giπ1,i,而(πJ)i=∑|V|i=1π1,i=1,即得证
对于π的计算,相当于解一个|V|元的方程,使用高斯消元,其中πM=π中的|V|个方程中是线性相关的(所有方程之和为0),删去其中任意一个即可
G−JM−I的计算
这四个矩阵通过前面,都可以在o(|V|3)内求出,但M−I并不一定满秩,因此不能用前面矩阵求逆的手段来计算
结论6(矩阵树定理):对于一张带权有向图G,令Mi,j={−e(i,j)(i≠j)∑nk=1e(i,k)(i=j),则矩阵M中去掉第i行和第i列,得到矩阵M′的行列式即所有以i为根的外向树边权乘积和
结论7:矩阵M−I的秩为|V|−1
将矩阵M−I的每一列求和,其结果都恰好为0,即M−I的秩小于|V|
显然I−M的秩与M−I相同,根据边权和为1的性质,其恰为G的矩阵M
根据矩阵树定理,去掉M−I的第i行和第i列,此时其行列式为以i为根的外向树边权乘积和,根据其强连通以及边权∈R+,不难证明其大于0
因此,去掉第i行第i列后其满秩,因此M−I的秩大于等于|V|−1
综上,即证明了M−I的秩为|V|−1
令A=G−J,B=M−I,即求AF=B
考虑令A的第i行乘上一个非0数或减去A的第j行,此时不难发现对于B的影响(在F不变下)也恰恰是让B的第i行乘上一个非0数或减去第j行
由此进行高斯消元,可以使得A中第i行仅有第i和|V|个元素非0(第|V|行全为0)
注意到Fi,i=0,因此有Bi,j=∑|V|k=1Ai,kFk,j,对i分类讨论:
1.若1≤i<|V|,即Bi,j=Fi,j+Ai,nFn,j
2.若i=|V|,由于A的第|V|行为0,因此Bi,j=0,且与F的值无关
通过i=j时,可以解出Fn,i=Bi,iAi,n,进而即可解出Fi,j=Bi,j−Ai,nFn,j
综上,我们就得到了一个时间复杂度为o(|V|3)的做法
(实现中可能因为一些精度误差而挂掉了QAQ)

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 405 4 #define eps 1e-8 5 int n,m,q,x,y,z,deg[N]; 6 double ans,M[N][N],A[N][N],B[N][N],f[N][N]; 7 void guess1(){ 8 for(int i=1;i<=n;i++){ 9 int k=-1; 10 for(int j=i;j<=n;j++) 11 if (fabs(A[j][i])>=eps){ 12 k=j; 13 break; 14 } 15 if (k!=i){ 16 for(int j=i;j<=n+1;j++)swap(A[i][j],A[k][j]); 17 } 18 double x=A[i][i]; 19 for(int j=i;j<=n+1;j++)A[i][j]/=x; 20 for(int j=i+1;j<=n;j++) 21 if (fabs(A[j][i])>=eps){ 22 double x=A[j][i]; 23 for(int k=i;k<=n+1;k++)A[j][k]-=A[i][k]*x; 24 } 25 } 26 for(int i=n;i;i--) 27 for(int j=i+1;j<=n;j++){ 28 A[i][n+1]-=A[i][j]*A[j][n+1]; 29 A[i][j]=0; 30 } 31 } 32 void guess2(){ 33 for(int i=1;i<n;i++){ 34 int k=-1; 35 for(int j=i;j<=n;j++) 36 if (fabs(A[j][i])>=eps){ 37 k=j; 38 break; 39 } 40 if (k!=i){ 41 for(int j=1;j<=n;j++){ 42 swap(A[i][j],A[k][j]); 43 swap(B[i][j],B[k][j]); 44 } 45 } 46 double x=A[i][i]; 47 for(int j=1;j<=n;j++){ 48 A[i][j]/=x; 49 B[i][j]/=x; 50 } 51 for(int j=i+1;j<=n;j++) 52 if (fabs(A[j][i])>=eps){ 53 double x=A[j][i]; 54 for(int k=1;k<=n;k++){ 55 A[j][k]-=A[i][k]*x; 56 B[j][k]-=B[i][k]*x; 57 } 58 } 59 } 60 for(int i=n-1;i;i--) 61 for(int j=1;j<i;j++) 62 if (fabs(A[j][i])>=eps){ 63 double x=A[j][i]; 64 for(int k=1;k<=n;k++){ 65 A[j][k]-=A[i][k]*x; 66 B[j][k]-=B[i][k]*x; 67 } 68 } 69 } 70 int main(){ 71 scanf("%d%d%d",&n,&m,&q); 72 for(int i=1;i<=m;i++){ 73 scanf("%d%d",&x,&y); 74 x++,y++; 75 deg[x]++; 76 M[x][y]++; 77 } 78 for(int i=1;i<=n;i++) 79 for(int j=1;j<=n;j++)M[i][j]=1.0*M[i][j]/deg[i]; 80 for(int i=1;i<n;i++) 81 for(int j=1;j<=n;j++)A[i][j]=M[j][i]-(i==j); 82 for(int i=1;i<=n;i++)A[n][i]=1; 83 A[n][n+1]=1; 84 guess1(); 85 for(int i=1;i<=n;i++)B[i][i]=1.0/A[i][n+1]; 86 for(int i=1;i<=n;i++) 87 for(int j=1;j<=n;j++)B[i][j]--; 88 for(int i=1;i<=n;i++) 89 for(int j=1;j<=n;j++)A[i][j]=M[i][j]-(i==j); 90 guess2(); 91 for(int i=1;i<=n;i++) 92 if (fabs(A[i][n])>=eps)f[n][i]=B[i][i]/A[i][n]; 93 for(int i=1;i<n;i++) 94 for(int j=1;j<=n;j++)f[i][j]=B[i][j]-A[i][n]*f[n][j]; 95 for(int i=1;i<=q;i++){ 96 scanf("%d%d",&x,&y); 97 y++; 98 ans=0; 99 for(int j=1;j<x;j++){ 100 scanf("%d",&z); 101 z++; 102 ans+=f[y][z]; 103 y=z; 104 } 105 printf("%.9f\n",ans); 106 } 107 }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单