bzoj3143 [Hnoi2013]游走
这个题是让你给遍赋权,问1-n路径的最小期望值。
显然只要我们知道了每一条边经过次数的期望值,我们就可以贪心地给边赋权了。但是要求边的期望值会很恶心,因为每条边正着走和反着走对其它边的贡献是不同的。于是我们考虑求每个点经过的次数的期望,那么每条边经过次数的期望就是它的端点的期望/端点的度数。
设f[i]表示i点经过次数的期望,那么f[i]=Σf[j]/d[j] (j->i)
注意一下边界条件,由于一开始就在1号点,所以f[1]=1+Σf[j]/d[j],而虽然n点会被经过好多次,但是n点对它连接的边是不会有贡献的,所以f[n]=0。
这样我们记可以高斯消元了。最后贪心赋边权,得到答案。
walk
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 1000 7 #define maxm 500000 8 #define eps 1e-9 9 #define inf 1000000000 10 using namespace std; 11 typedef double lb; 12 struct et 13 { 14 int s,t; 15 }e[maxm]; 16 lb a[maxn][maxn],v[maxn],w[maxm]; 17 int d[maxn],t[maxn][maxn]; 18 int n,m; 19 20 lb fab(lb x) 21 { 22 return (x>0)?x:-x; 23 } 24 void gauss(int n) 25 { 26 int k=1; 27 for (int i=1;i<=n;i++) 28 { 29 int p=0; 30 for (int j=k;j<=n;j++) 31 if (fab(a[i][j])>eps) { p=j; break; } 32 if (!p) continue; 33 for (int l=1;l<=n+1;l++) swap(a[p][l],a[k][l]); 34 for (int j=k+1;j<=n;j++) 35 { 36 lb rate=a[j][i]/a[k][i]; 37 for (int l=1;l<=n+1;l++) 38 a[j][l]-=a[k][l]*rate; 39 } 40 k++; 41 } 42 for (int i=n;i;i--) 43 { 44 v[i]=a[i][n+1]; 45 for (int j=i+1;j<=n;j++) 46 v[i]-=v[j]*a[i][j]; 47 v[i]/=a[i][i]; 48 } 49 } 50 51 void debug() 52 { 53 for (int i=1;i<=n;i++) 54 { 55 for (int j=1;j<=n+1;j++) 56 cout<<a[i][j]<<' '; 57 cout<<endl; 58 } 59 } 60 61 bool cmp(lb a,lb b) 62 { 63 return a>b; 64 } 65 66 int main() 67 { 68 scanf("%d%d",&n,&m); 69 int x,y; 70 for (int i=1;i<=m;i++) 71 { 72 scanf("%d%d",&x,&y); 73 e[i].s=x; e[i].t=y; 74 t[x][++d[x]]=y; 75 if (x==y) continue; 76 t[y][++d[y]]=x; 77 } 78 79 for (int i=1;i<=n-1;i++) 80 { 81 a[i][i]=1; 82 for (int j=1;j<=d[i];j++) 83 { 84 int k=t[i][j]; 85 if (k==n) continue; 86 a[i][k]-=1.0/d[k]; 87 } 88 } 89 n--; 90 a[1][n+1]=1; 91 //debug(); 92 gauss(n); 93 for (int i=1;i<=m;i++) w[i]=v[e[i].s]/(d[e[i].s]*1.0)+v[e[i].t]/(d[e[i].t]*1.0); 94 sort(w+1,w+m+1,cmp); 95 lb ans=0; 96 for (int i=1;i<=m;i++) 97 ans+=w[i]*i; 98 printf("%.3lf\n",ans); 99 return 0; 100 }
AC without art, no better than WA !