题目大意:给定一个无向连通图,我们需要给每条边附一个1~m的不重复的权值,使1到n的期望权值和最小
首先贪心思想是求出每条边的期望经过次数 然后对期望值最小的边附加m的权值,第二小的边附加m-1的权值,以此类推。
令f[i]为第i个点的期望经过次数 那么每条边的期望经过次数就是f[x]/d[x]+f[y]/d[y] 其中d[x]表示x的度数
那么显然有:
f[1]=1+Σ[1->j]f[j]/d[j]
f[i]=Σ[i->j]f[j]/d[j] (2<=i<=n-1)
其中f[n]应该等于1,但是由于进入了点n之后就不再出来,因此n点对周围的边和点的贡献都是0,不妨令f[n]=0
那么就有n个未知数n个方程 高斯消元求解即可
然后代入即可出解 注意求的是最小值不是最大值 因此最小的期望值应该乘最大的边权 不要弄反
边集又开小了- - 我是怎么了最近- -
#include <cmath> #include <cstdio> #include <cstring> #include <iomanip> #include <iostream> #include <algorithm> #define M 550 using namespace std; struct abcd{ int to,next; }table[M*M<<1]; int head[M],tot; int n,m,degree[M]; double f[M][M],a[M]; double expectation[M*M],ans; void Add(int x,int y) { degree[x]++; table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void Gauss_Elimination() { int i,j,k; for(i=1;i<=n;i++) { k=i; for(j=i+1;j<=n;j++) if( fabs(f[j][i])>fabs(f[k][i]) ) k=j; for(j=i;j<=n+1;j++) swap(f[i][j],f[k][j]); for(k=i+1;k<=n;k++) { double temp=-f[k][i]/f[i][i]; for(j=i;j<=n+1;j++) f[k][j]+=f[i][j]*temp; } } for(i=n;i;i--) { for(j=i+1;j<=n;j++) f[i][n+1]-=f[i][j]*a[j]; a[i]=f[i][n+1]/f[i][i]; } } int main() { int i,x,y; cin>>n>>m; for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); Add(x,y),Add(y,x); } for(x=1;x<n;x++) { f[x][x]-=1; if(x==1) f[x][n+1]=-1; for(i=head[x];i;i=table[i].next) f[x][table[i].to]+=1.0/degree[table[i].to]; } f[n][n]=1;f[n][n+1]=0; Gauss_Elimination(); for(i=1;i<=m;i++) { x=table[i+i-1].to; y=table[i<<1].to; expectation[i]=a[x]/degree[x]+a[y]/degree[y]; } sort(expectation+1,expectation+m+1); for(i=1;i<=m;i++) ans+=(m-i+1)*expectation[i]; cout<<fixed<<setprecision(3)<<ans<<endl; return 0; }
BZOJ 3143 HNOI2013 游走 期望DP+高斯消元
原文地址:http://blog.csdn.net/popoqqq/article/details/42234607