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;
}

浙公网安备 33010602011771号