[HNOI2013]随机游走(高斯消元)
Link (https://www.luogu.org/problemnew/show/P3232)
题义
一个n(<=500)个点,m条边的无向简单联通图,从一号点出发随机游走,每到一个点都会随机选择一条出边接着往下走,到n号点时停止。定义得分为经过的所有边的编号之和,求经过调整边的编号,一次随机游走的期望得分最小值。
求出每条边的期望经过次数然后贪心即可
经过一条边的期望次数可以由它两端的点被经过的期望次数推出。记p[i]为经过点i的期望次数,d[i]为点i的出度,则连接u,v的边被经过的期望次数为 Q[x]=p[u]/d[u]*(u!=n)+p[v]/d[v]*(v!=n) (到n时就终止了,不会再走出)
对于每一个点列一个方程组:p[u]=Sigma(p[v]/d[v]) (u->v,v!=n)
需要注意:
1.p[n]=1
2.p[1]-Sigma(p[v]/d[v])=1 (初始经过的一次)
1 #include <cmath> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <algorithm> 5 using namespace std; 6 #define gc getchar() 7 inline int gi(){ 8 int x(0);char c(gc); 9 while(c<'0'||'9'<c)c=gc; 10 while('0'<=c&&c<='9')x=x*10+c-'0',c=gc; 11 return x; 12 } 13 const int N=550,M=250050; 14 int n,m; int d[N]; int e[M][2]; 15 16 //-----Qxx-----> 17 int head[N],ver[M<<1],Next[M<<1],tot=0; 18 void add_edge(int u,int v){ 19 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 20 ver[++tot]=u,Next[tot]=head[v],head[v]=tot; 21 } 22 23 void input(){ 24 n=gi(),m=gi(); 25 for(int i=1,u,v;i<=m;i++){ 26 u=gi(),v=gi(); d[u]++,d[v]++; 27 add_edge(u,v); e[i][0]=u,e[i][1]=v; 28 } 29 } 30 31 //-----Gau-----> 32 double f[N][N],p[N]; 33 void Setup() 34 { 35 for(int x=1;x<=n;x++){ 36 f[x][x]=1.0; 37 if(x==n){ f[x][n+1]=1.0; continue ;} 38 if(x==1) f[x][n+1]=1.0; 39 for(int i=head[x];i;i=Next[i]){ 40 int v=ver[i]; if(v==n) continue ; 41 f[x][v]=-1.0/d[v]; 42 } 43 } 44 } 45 46 void Guass() 47 { 48 for(int i=1;i<n;i++){ 49 int ps=i; double Mx=0.0; 50 for(int j=i;j<=n;j++) if(fabs(f[i][j])>Mx) Mx=fabs(f[i][j]),ps=j; 51 swap(f[i],f[ps]); 52 for(int j=i+1;j<=n;j++){ 53 double t=f[j][i]/f[i][i]; 54 for(int k=i;k<=n+1;k++) f[j][k]-=t*f[i][k]; 55 } 56 } 57 for(int i=n;i>=1;i--){ 58 p[i]=f[i][n+1]/f[i][i]; 59 for(int j=1;j<i;j++) f[j][n+1]-=f[j][i]*p[i]; 60 } 61 } 62 63 double Q[M]; 64 void calc_edge() 65 { 66 for(int i=1;i<=m;i++){ 67 int u=e[i][0],v=e[i][1]; 68 Q[i]=p[u]/d[u]*(u!=n)+p[v]/d[v]*(v!=n); 69 } 70 } 71 72 void work() 73 { 74 Setup(); 75 Guass(); 76 calc_edge(); 77 sort(Q+1,Q+m+1); double ans=0; 78 for(int i=1,j=m;i<=m;i++,j--){ 79 ans+=Q[i]*j; 80 } 81 printf("%.3lf\n",ans); 82 } 83 84 85 int main() 86 { 87 input(); 88 work(); 89 return 0; 90 }