P2351 - 【HNOI2013】游走
Description
一个无向连通图,顶点从1编号到N,边从1编号到M。
小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。
现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。
Input
第一行是正整数N和M,分别表示该图的顶点数 和边数;
接下来M行每行是整数u,v(1≤u,v≤N),表示顶点u与顶点v之间存在一条边。
输入保证30%的数据满足N≤10,100%的数据满足2≤N≤500且是一个无向简单连通图。
Output
仅包含一个实数,表示最小的期望值,保留3位小数。
Sample Input
3 3
2 3
1 2
1 3
Sample Output
3.333
Hint
样例提示:
边(1,2)编号为1,边(1,3)编号2,边(2,3)编号为3。
由于搬运者发现官方数据没有程序能跑对最后两个点,遂修改其结果。
先算出到每个点的期望值f[i]=Σf[to]/deg[to],然后因为1是起点所以f[1]还要加1。
然后可以发现这个式子的意思就是f[i]加上每个可以走到i这个点的期望*走到i的概率,
因为走到n就不能走了,所以为了消除n对别的点的影响,f[n]=0。
其实我推方程半天没推出来就是因为这个f[n]=0,还有f[1]要加1。
然后就可以高斯消元法解方程,这样就可以把点的期望求出来了。
然后边的期望就是p[i]=p[u]/deg[u]+p[v]/deg[v]。(u,v是这条边连的两个点)。
然后贪心算答案就可以了。
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<ctime> 6 #include<cmath> 7 #include<string> 8 #include<vector> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 #define maxn 510 15 using namespace std; 16 struct data{ 17 int nex,to; 18 }e[maxn*maxn*2]; 19 double deg[maxn],a[maxn][maxn],p[maxn*maxn]; 20 int head[maxn],edge=0,n; 21 void add(int from,int to){ 22 e[++edge].nex=head[from]; 23 e[edge].to=to; 24 head[from]=edge; 25 } 26 void gauss(){ 27 for(int i=1;i<=n;i++){ 28 int t=i; 29 while(!a[t][i] && t<=n) t++; 30 if(t>n) continue; 31 for(int j=1;j<=n+1;j++) swap(a[t][j],a[i][j]); 32 double k=a[i][i]; 33 for(int j=i;j<=n+1;j++) a[i][j]/=k; 34 for(int j=1;j<=n;j++) 35 if(j!=i && a[j][i]){ 36 k=a[j][i]; 37 for(int p=i;p<=n+1;p++) 38 a[j][p]-=k*a[i][p]; 39 } 40 } 41 } 42 bool cmp(const double &a,const double &b){ 43 return a>b; 44 } 45 int main() 46 { 47 freopen("walk.in","r",stdin); 48 freopen("walk.out","w",stdout); 49 int m,x,y; 50 scanf("%d%d",&n,&m); 51 for(int i=1;i<=m;i++){ 52 scanf("%d%d",&x,&y); 53 add(x,y),add(y,x),deg[x]++,deg[y]++; 54 } 55 for(int i=1;i<n;i++){ 56 if(i==1) a[i][n+1]=1; 57 a[i][i]=1; 58 for(int j=head[i];j;j=e[j].nex) 59 a[i][e[j].to]-=1/deg[e[j].to]; 60 } 61 a[n][n]=0; 62 gauss(); 63 for(int i=1;i<=edge;i+=2) 64 p[(i+1)/2]=(a[e[i].to][n+1]/deg[e[i].to])+(a[e[i+1].to][n+1]/deg[e[i+1].to]); 65 sort(p+1,p+m+1,cmp); 66 double ans=0.0; 67 for(int i=1;i<=m;i++) 68 ans+=p[i]*i; 69 printf("%.3lf",ans); 70 return 0; 71 }