bzoj3143[Hnoi2013]游走 期望
显而易见,要最小化总分就要让期望经过次数最多的边权值最小。
而边的期望可以通过点的期望导出。
点的期望又可以通过和它相连的点的权值导出。
就可以列成一组方程。
再高斯消元一下就可以解出来了。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const double eps=1e-8; inline double max(double x,double y){ return x>y?x:y; } inline double abs(double x){ return max(x,-x); } inline void swap(double &x,double &y){ double z=x;x=y;y=z; } inline bool cmp(const double &a,const double &b){ return a>b; } inline int read(){ int x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-'){f=-1;}ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m; int u[250005],v[250005]; int map[505][505],du[505]; double a[505][505],res[505],val[250005]; inline void guess(){ int i,j,k,r; double t; for(i=1;i<=n-1;i++){ r=i; for(j=i+1;j<=n;j++) if(abs(a[j][i])>abs(a[r][i])+eps) r=j; for(j=i;j<=n+1;j++) swap(a[r][j],a[i][j]); for(j=i+1;j<=n;j++){ t=a[j][i]/a[i][i]; for(k=i;k<=n+1;k++) a[j][k]-=a[i][k]*t; } } for(i=n;i>0;i--){ t=0; for(j=i+1;j<=n;j++) t+=a[i][j]*res[j]; res[i]=(a[i][n+1]-t)/a[i][i]; } } int main(){ n=read(),m=read(); int i,x,y,j; double ans=0; for(i=1;i<=m;i++){ x=read(),y=read();u[i]=x,v[i]=y; map[x][y]=1;map[y][x]=1;du[x]++;du[y]++; } for(i=1;i<=n-2;i++) for(j=1;j<=n-1;j++){ if(map[i][j]) a[i][j]=1.0/du[j]; if(i==j) a[i][j]=-1; } a[n-1][n]=1; for(i=1;i<=n-2;i++) a[i][n]=(i-1)?0:(-1); for(i=1;i<=n-1;i++) a[n-1][i]=1.0*map[n][i]/du[i]; n--;guess(); for(i=1;i<=m;i++) val[i]=1.0/du[u[i]]*res[u[i]]+1.0/du[v[i]]*res[v[i]]; sort(val+1,val+1+m,cmp); for(i=1;i<=m;i++) ans+=val[i]*i; printf("%.3lf\n",ans+eps); return 0; }