bzoj 3143 [Hnoi2013]游走 期望dp+高斯消元
[Hnoi2013]游走
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3394 Solved: 1493
[Submit][Status][Discuss]
Description
一个无向连通图,顶点从1编号到N,边从1编号到M。
小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。
现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。
Input
第一行是正整数N和M,分别表示该图的顶点数 和边数,接下来M行每行是整数u,v(1≤u,v≤N),表示顶点u与顶点v之间存在一条边。 输入保证30%的数据满足N≤10,100%的数据满足2≤N≤500且是一个无向简单连通图。
Output
仅包含一个实数,表示最小的期望值,保留3位小数。
Sample Input
3 3
2 3
1 2
1 3
2 3
1 2
1 3
Sample Output
3.333
HINT
边(1,2)编号为1,边(1,3)编号2,边(2,3)编号为3。
Source
题解:
很好想的,列出期望方程,对于每个点,都有一个方程,n-1个方程
解n-1个元,g[i]表示到达终点还需要多少。
即可,发现一条边,只会在到u或者v产生贡献。
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #define N 507 7 #define M 250007 8 9 using namespace std; 10 11 int n,m; 12 int U[M],V[M],d[N]; 13 double a[N][N],x[N],w[M],ans; 14 15 void Gauss(int n,int m) 16 { 17 int i,j,k; 18 for(i=1;i<m;i++) 19 { 20 for(k=i,j=i+1;j<=n;j++)if(fabs(a[k][i])<fabs(a[j][i]))k=j; 21 if(i!=k)for(j=i;j<=m;j++)swap(a[i][j],a[k][j]); 22 for(j=i+1;j<=n;j++) 23 { 24 double rate=a[j][i]/a[i][i]; 25 for(k=i;k<=m;k++)a[j][k]-=a[i][k]*rate; 26 } 27 } 28 for(i=m-1;i;i--) 29 { 30 for(j=i+1;j<m;j++)a[i][m]-=a[i][j]*x[j]; 31 x[i]=a[i][m]/a[i][i]; 32 } 33 } 34 int main() 35 { 36 int i; 37 38 scanf("%d%d",&n,&m); 39 for(i=1;i<=m;i++) 40 { 41 scanf("%d%d",&U[i],&V[i]); 42 d[U[i]]++,d[V[i]]++; 43 } 44 for(i=1;i<n;i++)a[i][i]=-1; 45 for(i=1;i<=m;i++) 46 { 47 a[U[i]][V[i]]+=1.0/d[V[i]]; 48 a[V[i]][U[i]]+=1.0/d[U[i]]; 49 } 50 for(i=1;i<=n;i++)a[n][i]=0; 51 a[1][n+1]=-1,a[n][n]=1; 52 Gauss(n,n+1); 53 for(i=1;i<=m;i++)w[i]=x[U[i]]/d[U[i]]+x[V[i]]/d[V[i]]; 54 sort(w+1,w+m+1); 55 for(i=1;i<=m;i++)ans+=(m-i+1)*w[i]; 56 printf("%.3lf\n",ans); 57 }