一看就是高斯消元。
但没想到边的期望经过次数=点的期望 / 点的度数
官方数据有误。
我的代码在gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 下可以过。
在 gcc 4.6.3 g++ Main.cc -o Main -Wall -lm --static -DONLINE_JUDGE 下可以过 (去掉-O2)
/**
* Problem:HNOI2013-d2p2
* Author:Shun Yao
* Time:2013.5.28
* Result:Accepted
* Memo:DP, greedy, guass
*/
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
const long Maxn = 505;
long n, m, d[Maxn];
double a[Maxn][Maxn], w[Maxn];
class lnode {
public:
long u, v;
lnode() {}
~lnode() {}
} line[Maxn * Maxn >> 1];
bool cmpa(double x, double y) {
return x > y;
}
int main() {
freopen("d2p2.in", "r", stdin);
freopen("d2p2.out", "w", stdout);
scanf("%ld%ld", &n, &m);
memset(d, 0, sizeof d);
for (long i = 1; i <= m; ++i) {
scanf("%ld%ld", &line[i].u, &line[i].v);
++d[line[i].u];
++d[line[i].v];
}
for (long i = 1; i < n; ++i)
a[i][i] = 1.0;
a[1][0] = 1.0;
for (long i = 1; i <= m; ++i) {
if (line[i].u == n || line[i].v == n)
continue;
a[line[i].u][line[i].v] -= 1.0 / d[line[i].v];
a[line[i].v][line[i].u] -= 1.0 / d[line[i].u];
}
for (long i = 1; i < n; ++i) {
long pos;
for (long j = i; j < n; ++j) {
if (fabs(a[j][i]) > 1e-16) {
pos = j;
break;
}
}
if (pos != i) {
std::swap(a[pos][0], a[i][0]);
for (long j = i; j < n; ++j)
std::swap(a[pos][j], a[i][j]);
}
for (long j = i + 1; j < n; ++j)
if (fabs(a[j][i]) > 1e-16) {
double x = a[j][i] / a[i][i];
a[j][0] -= a[i][0] * x;
for (long k = i; k < n; ++k)
a[j][k] -= a[i][k] * x;
}
}
for (long i = n - 1; i; --i) {
for (long j = i + 1; j < n; ++j)
a[i][0] -= a[i][j] * a[j][0];
a[i][0] /= a[i][i];
}
for (long i = 1; i <= m; ++i)
w[i] = a[line[i].u][0] / d[line[i].u] + a[line[i].v][0] / d[line[i].v];
std::sort(w + 1, w + m + 1, cmpa);
double ans = 0.0;
for (long i = 1; i <= m; ++i)
ans += i * w[i];
printf("%.3lf", ans);
fclose(stdin);
fclose(stdout);
return 0;
}