3143: [Hnoi2013]游走
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2240 Solved: 981
[ 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
2 3
1 2
1 3
Sample Output
3.333
HINT
边
(1,2)
编号为
1
,边
(1,3)
编号
2
,边
(2,3)
编号为
3
。
Source
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
typedef double DB;
const int maxn = 505;
const int maxm = maxn*maxn;
const DB eps = 1E-9;
const DB INF = 1E12;
const DB K = 1E4;
struct E{
int x,y; E(){}
E(int x,int y): x(x),y(y){}
}edgs[maxm];
int n,m;
DB du[maxn],f[maxn],a[maxn][maxn],b[maxn],G[maxm];
vector <int> v[maxn];
void Gauss(int k)
{
DB Max = -INF; int pos;
if (k == n)
{
if (fabs(a[k][k]) <= eps) f[k] = 0;
else f[k] = b[k]/a[k][k];
return;
}
for (int i = k; i <= n; i++)
if (fabs(a[i][k]) > Max) Max = fabs(a[i][k]),pos = i;
if (Max <= eps) {Gauss(k + 1); return;}
for (int i = k; i <= n; i++) swap(a[k][i],a[pos][i]); swap(b[k],b[pos]);
DB T = a[k][k];
for (int i = k; i <= n; i++) a[k][i] /= T; b[k] /= T;
for (int i = k + 1; i <= n; i++)
if (fabs(a[i][k]) >= eps)
{
T = a[i][k]; b[i] -= b[k]*T;
for (int j = k; j <= n; j++)
a[i][j] -= a[k][j]*T;
}
Gauss(k + 1);
DB tot = b[k];
for (int i = k + 1; i <= n; i++)
tot -= f[i]*a[k][i];
f[k] = tot;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
//freopen("test.txt","w",stdout);
#endif
cin >> n >> m; --n;
for (int i = 1; i <= m; i++)
{
int x,y; scanf("%d%d",&x,&y);
edgs[i] = E(x,y);
du[x] += 1.00; du[y] += 1.00;
v[x].push_back(y);
v[y].push_back(x);
}
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < v[i].size(); j++)
{
int to = v[i][j];
if (to == n + 1) continue;
a[i][to] = -K/du[to];
}
a[i][i] += K;
}
b[1] = K; Gauss(1);
//for (int i = 1; i <= n; i++)
//printf("%d : %.3lf\n",i,a[i][i]);
for (int i = 1; i <= m; i++)
{
E e = edgs[i];
G[i] = f[e.x]/du[e.x] + f[e.y]/du[e.y];
}
sort(G + 1,G + m + 1);
DB M = m,Ans = 0;
for (int i = 1; i <= m; i++) Ans += G[i]*M,M -= 1.00;
if (Ans >= 1E-4) printf("%.3lf",Ans); else printf("0.000");
return 0;
}