bzoj 3143 [Hnoi2013]游走(贪心,高斯消元,期望方程)
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=3143
【题意】
给定一个无向图,从1走到n,走过一条边得到的分数为边的标号,问一个边的标号方法,使得路径上得分最少。
【思路】
设f[i]表示经过i点的期望次数。有:
f[1]=1+sigma{ f[v] }
f[u]=sigma{ f[v] }
特别地,令f[n]=0,因为n点不会对任何连边做出贡献,于是记之为0。
于是得到了n个线性方程组,可以用高斯消元法求解。
对于一条边(u,v)的期望经过次数为:
e=f[u]/du[u] + f[v]/du[v]
du[u]为u点的度数。
然后对每条边贪心地赋值,期望经过次数越大地赋值越小。
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 505; 15 const int M = N*N; 16 17 ll read() { 18 char c=getchar(); 19 ll f=1,x=0; 20 while(!isdigit(c)) { 21 if(c=='-') f=-1; c=getchar(); 22 } 23 while(isdigit(c)) 24 x=x*10+c-'0',c=getchar(); 25 return x*f; 26 } 27 28 struct Edge { 29 int v,nxt; 30 }e[M]; 31 int en=1,front[N]; 32 void adde(int u,int v) 33 { 34 e[++en]=(Edge){v,front[u]}; front[u]=en; 35 } 36 37 int n,m,du[N],flag[N][N]; 38 double ef[N],a[N][N]; int tot; 39 40 void gause() 41 { 42 for(int i=1;i<=n;i++) 43 { 44 int r=i; 45 for(int j=i+1;j<=n;j++) 46 if(fabs(a[j][i])>fabs(a[r][i])) r=i; 47 if(r!=i) for(int j=1;j<=n+1;j++) swap(a[i][j],a[r][j]); 48 for(int j=n+1;j>=i;j--) 49 for(int k=i+1;k<=n;k++) 50 a[k][j]-=a[k][i]/a[i][i]*a[i][j]; 51 } 52 for(int i=n;i;i--) 53 { 54 for(int j=i+1;j<=n;j++) 55 a[i][n+1]-=a[i][j]*a[j][n+1]; 56 a[i][n+1]/=a[i][i]; 57 } 58 } 59 60 int main() 61 { 62 n=read(),m=read(); 63 int u,v; 64 FOR(i,1,m) 65 { 66 u=read(),v=read(); 67 adde(u,v),adde(v,u); 68 du[u]++,du[v]++; 69 } 70 FOR(u,1,n-1) 71 { 72 if(u==1) a[u][n]=1; 73 a[u][u]=1; 74 trav(u,i) 75 { 76 int v=e[i].v; 77 if(v!=n) a[u][v]-=1.0/du[v]; 78 } 79 } 80 a[1][n]=1; 81 n--; 82 gause(); 83 FOR(u,1,n) 84 { 85 trav(u,i) 86 { 87 int v=e[i].v; 88 if(v!=u&&!flag[u][v]) 89 ef[++tot]=a[u][n+1]/du[u]+a[v][n+1]/du[v], 90 flag[u][v]=flag[v][u]=1; 91 } 92 } 93 sort(ef+1,ef+tot+1); 94 double ans=0.0; 95 FOR(i,1,tot) 96 ans+=ef[i]*(tot-i+1); 97 printf("%.3lf\n",ans); 98 return 0; 99 }
posted on 2016-03-31 16:43 hahalidaxin 阅读(310) 评论(0) 编辑 收藏 举报