bzoj3143游走——期望+高斯消元
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3143
只需算出每条边被经过的概率,将概率从小到大排序,从大到小编号,就可得到最小期望;
每条边经过的概率是其两端的点被走的次数/该点的度数的和;
而每个点被走的次数又需要从与其相连的点推过来,所以构成n个n元方程,进行高斯消元求解;
其中点n较为特殊,可以不去管它,因为所有路径到n后就不再走出来,也就是n到n的概率为0;
而因为所有路径从点1开始,所以1的次数平地+1。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int const M=505*505; int n,m,u[M],v[M],d[505]; double a[505][505],ans,x[505],w[M]; void gauss() { for(int i=1;i<n;i++) { int k=i; for(int j=i+1;j<n;j++) if(fabs(a[j][i])>fabs(a[k][i]))k=j;//fabs if(k!=i) for(int l=i;l<=n+1;l++)swap(a[k][l],a[i][l]); for(int l=i+1;l<n;l++) { double r=a[l][i]/a[i][i];//不是k!!! for(int t=i;t<=n+1;t++) a[l][t]-=r*a[i][t]; } } x[n]=0;//!!! for(int i=n-1;i;i--) { for(int j=i+1;j<n;j++)a[i][n+1]-=a[i][j]*x[j]; x[i]=a[i][n+1]/a[i][i]; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&u[i],&v[i]); d[u[i]]++;d[v[i]]++; } for(int i=1;i<=m;i++) { a[u[i]][v[i]]+=1.0/d[v[i]]; a[v[i]][u[i]]+=1.0/d[u[i]]; } for(int i=1;i<n;i++)a[i][i]=-1; a[1][n+1]=-1; gauss(); // for(int i=1;i<=n;i++) // printf("x[%d]=%.3lf\n",i,x[i]); for(int i=1;i<=m;i++) w[i]=x[u[i]]/d[u[i]]+x[v[i]]/d[v[i]]; sort(w+1,w+m+1); for(int i=1;i<=m;i++) ans+=(m-i+1)*w[i]; printf("%.3lf",ans); return 0; }