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

猜你喜欢

转载自www.cnblogs.com/Shyninswain/p/10852786.html
今日推荐