3143: [Hnoi2013]游走
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 4289 Solved: 2008
[Submit][Status][Discuss]
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。
#include<bits/stdc++.h> using namespace std; const int N=505; int n,m; int mp[N][N],deg[N]; double mt[N][N],dp[N]; struct edge { int s,t; }e[N*N]; void solve(int now) { if(now==n) return; if(mt[now][now]==0) { for(int i=now+1;i<n;++i) if(mt[i][now]!=0) { for(int j=now;j<=n+1;++j) swap(mt[now][j],mt[i][j]); break; } } for(int i=now+1;i<n;++i) { double tmp=-mt[i][now]/mt[now][now]; for(int j=now;j<=n+1;++j) mt[i][j]+=tmp*mt[now][j]; } //print(); solve(now+1); dp[now]=mt[now][n+1]/mt[now][now]; //cout<<dp[now]<<endl; for(int i=now-1;i>=1;--i) mt[i][n+1]-=dp[now]*mt[i][now]; } bool cmp(edge u,edge v) { return dp[u.s]+dp[u.t]>dp[v.s]+dp[v.t]; } int main() { int cnt=0; scanf("%d%d",&n,&m); memset(mp,-1,sizeof(mp)); for(int i=1;i<=m;++i) { int a,b; scanf("%d%d",&a,&b); e[i].s=a,e[i].t=b; mp[a][b]=mp[b][a]=1; ++deg[a],++deg[b]; } mt[1][n+1]=-1.0; for(int i=1;i<n;++i) for(int j=1;j<=n;++j) { if(i==j) mt[i][i]=-1.0; if(mp[i][j]<0) continue; ++cnt; mt[i][j]=1.0/(double)deg[i]; } //print(); solve(1); sort(e+1,e+m+1,cmp); for(int i=1;i<=m;++i) { mp[e[i].s][e[i].t]=mp[e[i].t][e[i].s]=i; // cout<<e[i].s<<" "<<e[i].t<<endl; } for(int i=1;i<n;++i) for(int j=1;j<=n+1;++j) mt[i][j]=0.0; for(int i=1;i<n;++i) for(int j=1;j<=n;++j) { if(i==j) mt[i][i]=-1.0; if(mp[i][j]<0) continue; ++cnt; mt[i][j]=1.0/(double)deg[i]; mt[i][n+1]-=(double)mp[i][j]/deg[i]; } solve(1); printf("%.3lf",dp[1]); return 0; }
原文地址:https://www.cnblogs.com/w19567/p/11247449.html
时间: 2024-10-13 00:05:18