考虑用递推解决,设
表示当前走到
节点,上一次到达的是
节点,最终回到
节点的路径长度的期望。
容易得:
;
注意到这个方程式是不能直接递推的,将 项移到等号左侧,得到一个 元线性方程组,那么我们就可以用高斯消元解出分别以 为未知数的 个方程组。这么做需要的复杂度为 ,考虑优化。
仔细观察我们得到的这个线性方程组,为分析方便,我们将二元组 映射为一个整数 ,将由 的递推式产生的方程放置于矩阵的第 行。显然的,有:
其余项皆为
考虑在消元时,矩阵中非
项的变化。我们将
中
相同的方程称为一组,显然的,不同组的出边产生的非
项的位置交集为空,且在消元时同一组内的方程必然不可能产生交互。可以发现,每次完成对一个组的消元,我们的矩阵中将有
个列变得非
,且这
个列在区间
中各有一个,所以对于第
个进行消元的组,将会有
个方程的行变换次数为
,其余的方程行变换次数为
。前者产生的总行变换次数为
,后者的次数需要仔细计算:
所以实际上在 时,一次消元产生的总行变换次数只有 次左右。那么总复杂度为 ,实际的数字会更小一些。
因为垃圾蓝桥OJ没有对这题使用SPJ,所以以下代码只能拿65分(题目上已经标明误差范围但OJ没有使用SPJ判断),懒得再优化精度了。只能说:
珍爱生命,远离蓝翔杯。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
const int up=21;const double eps=1e-9;
struct eg{int u,v,nx;}gp[10010];int cnt,hd[up+10],n,m,od[up+10];double mt[900][900],tm[900][900];
inline void psh(int u,int v){++cnt;gp[cnt].u=u,gp[cnt].v=v,gp[cnt].nx=hd[u],hd[u]=cnt;};
inline int _btn(int a,int b){return a*n+b;};
inline int _seg(int a,int b){return a==b?0:1;};
inline bool _dmp(double a,double b){return fabs(b-a)<=eps;};
inline void _swp(int a,int b,int n){int i,j;for(i=0;i<=n;++i)swap(mt[a][i],mt[b][i]);};
inline void _ppt(int a,int b,int n,double x){int i,j;for(i=0;i<=n;++i)mt[b][i]-=x*mt[a][i];};
void guess(int n){
int i,j,k,d;double xq;for(i=0;i<n;++i){
for(k=i+1;k<n;++k)if(!_dmp(mt[k][i],0.))_ppt(i,k,n,mt[k][i]/mt[i][i]);
}
for(i=n-1;i>=0;--i){
for(j=n-1;j>i;--j)mt[i][n]-=mt[j][n]*mt[i][j];
if(!_dmp(mt[i][i],0.))mt[i][n]/=mt[i][i];
}
};
void _initi(int d,int n){
int i,j,t,z=sqrt(n);for(i=0;i<n;++i)for(j=0;j<=n;++j)mt[i][j]=tm[i][j];
for(i=0;i<z;++i)if(i!=d){
for(t=_btn(d,i),j=0;j<=n;mt[t][j++]=0.);mt[t][t]=1.0;
}
};
void cl(){
int i,j,k,d,t,a,b;double xq;scanf("%d %d",&n,&m);for(clr(hd),cnt=0,clr(od),i=0;i<m;++i){
scanf("%d %d",&a,&b);--a,--b;psh(a,b),psh(b,a);od[a]++,od[b]++;
}
int dn=n*n;for(i=0;i<dn;++i)for(j=0;j<dn;mt[i][j++]=0.);
for(k=i=0;i<n;++i)for(j=0;j<n;++j,++k){
mt[k][k]=1.0,xq=1.0/(double)(od[i]-_seg(i,j));
for(t=hd[i];t;t=gp[t].nx)if(gp[t].v!=j){
mt[k][_btn(gp[t].v,i)]=-xq,mt[k][dn]=1.0;
}
}
for(i=0;i<dn;++i)for(j=0;j<=dn;++j)tm[i][j]=mt[i][j];
for(i=0;i<n;++i){
_initi(i,dn);guess(dn);printf("%.12lf\n",mt[_btn(i,i)][dn]);
}
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
cl();
return 0;
};