bzoj3143 游走 概率 高斯消元
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3143
题目大意是说:给出一张无向图,找出一种加权值的方式,使得从1到n期望带权路径长度最短,输出最短路长度。
首先,根据基本常识,走的次数多的边,权值越小越好(废话)。
于是问题转变为:找出每条边的期望经过次数。
设i边期望经过次数为f[i],则f[i]就为两个端点期望经过次数与走到这条边概率之商的和(没看懂?就是f[i]=x[duan1]/du[duan1]+x[duan2]/du[duan2],x[i]表示i点期望经过次数,du[i]表示i点在图中的度)。
问题进一步转化为:找出每个点的期望经历次数。
首先,由于我们走过终点就可以不走了,所以我们忽略掉n节点。
根据期望的线性性可以得出x[i]=sigma{(x[j]+1)/du[j]}。
把每个点的情况都弄出来,就会发现这是一个有n个变量,n个式子的线性方程组。
于是用死也打不对的高斯消元解决。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 const int maxn=505,maxm=500005; 8 const double eps=1e-7; 9 struct node 10 { 11 int from,to,next; 12 }edge[maxm]; 13 int head[maxn],tot; 14 void addedge(int u,int v) 15 { 16 edge[++tot]=(node){u,v,head[u]};head[u]=tot; 17 } 18 int du[maxn],n,m; 19 double a[maxn][maxn],x[maxn],f[maxm]; 20 void Gauss() 21 { 22 int im,num=1; 23 for(int k=1;k<=n;k++,num++) 24 { 25 im=k; 26 for(int i=k+1;i<=n;i++) 27 if(fabs(a[i][k])>fabs(a[im][k]))im=i; 28 if(im!=k) 29 for(int i=k;i<=n+1;i++)swap(a[num][i],a[im][i]); 30 if(fabs(a[num][k])==0) 31 { 32 num--; 33 continue; 34 } 35 for(int i=num+1;i<=n;i++) 36 { 37 if(!a[num][i])continue; 38 double t=a[i][k]/a[num][k]; 39 for(int j=k;j<=n+1;j++) 40 a[i][j]-=t*a[k][j]; 41 } 42 } 43 for(int i=n;i>=1;i--) 44 { 45 for(int j=n;j>=i+1;j--) 46 a[i][n+1]-=x[j]*a[i][j]; 47 x[i]=a[i][n+1]/a[i][i]; 48 } 49 } 50 bool cmp(double a,double b) 51 { 52 return a>b; 53 } 54 int haha() 55 { 56 //freopen("walk.in","r",stdin); 57 //freopen("walk.out","w",stdout); 58 scanf("%d%d",&n,&m); 59 for(int i=1;i<=m;i++) 60 { 61 int a,b;scanf("%d%d",&a,&b); 62 du[a]++;du[b]++; 63 addedge(a,b);addedge(b,a); 64 } 65 a[1][n--]=-1; 66 for(int i=1;i<=n;i++) 67 { 68 a[i][i]=-1; 69 for(int j=head[i];j;j=edge[j].next) 70 { 71 int v=edge[j].to; 72 if(v!=n+1) 73 a[i][v]+=(double)1/(du[v]); 74 } 75 } 76 Gauss(); 77 for(int i=1;i<=tot;i++) 78 f[(i-1)>>1]+=x[edge[i].to]/du[edge[i].to]; 79 sort(f,f+m,cmp); 80 double ans=0; 81 for(int i=0;i<m;i++)ans+=f[i]*(i+1); 82 printf("%0.3lf\n",ans); 83 } 84 int sb=haha(); 85 int main(){;}
只要是活着的东西,就算是神我也杀给你看。