Processing math: 99%

[gym101981F]Frank

在本题中,每一步是独立的,因此即可以看作从s移动到t的期望步数(对于每一对st都求出答案)

fi,j表示当s=it=j时的答案,则有fi,j={(i,k)nw(i,k)fk,j+1(ij)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+1gi,i=0(即恰好为0)

构造矩阵Mi,j=w(i,j)Fi,j=fi,jGi,j={gi(i=j)0(ij)以及全1矩阵Ji,j=1,那么根据前面的递推式,就可以得到MF+JG=F

进而,即(MI)F=GJ,问题即变为求G以及GJMI

G的计算

再构造一个1×|V|的矩阵π,满足|V|i=1π1,i=1πM=π

结论5:1in,giπ1,i=1

考虑条件MF+JG=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),删去其中任意一个即可

GJMI的计算

这四个矩阵通过前面,都可以在o(|V|3)内求出,但MI并不一定满秩,因此不能用前面矩阵求逆的手段来计算

结论6(矩阵树定理):对于一张带权有向图G,令Mi,j={e(i,j)(ij)nk=1e(i,k)(i=j),则矩阵M中去掉第i行和第i列,得到矩阵M的行列式即所有以i为根的外向树边权乘积和

结论7:矩阵MI的秩为|V|1

将矩阵MI的每一列求和,其结果都恰好为0,即MI的秩小于|V|

显然IM的秩与MI相同,根据边权和为1的性质,其恰为G的矩阵M

根据矩阵树定理,去掉MI的第i行和第i列,此时其行列式为以i为根的外向树边权乘积和,根据其强连通以及边权R+,不难证明其大于0

因此,去掉第i行第i列后其满秩,因此MI的秩大于等于|V|1

综上,即证明了MI的秩为|V|1

A=GJB=MI,即求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.若1i<|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,jAi,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 }
View Code
复制代码

 

posted @   PYWBKTDA  阅读(115)  评论(0编辑  收藏  举报
编辑推荐:
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
阅读排行:
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单
点击右上角即可分享
微信分享提示