题意:给一个无向图,给边附上1~M的权值,使得1到N的期望得分最小。
显然应该让期望经过次数最多的边的权值尽量小。但是由于这是个无向图,肯定有环,可以无限制走,不是很好确定概率。事实上可以发现虽然可以无限走,但是走到每个点的概率之间是相互制约的,也就是可以列一些方程出来,设f[i]为i走到节点的概率,则f[i]=Σf[j]/du[j],其中j到i右边,du表示每个点的度。然后由于是从1开始的,1的期望一开始设置为1。然后用高斯约当强行解这个方程即可。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) const int inf = 0x3f3f3f3f; #define DB double const int MAXN = 505; int n, m; DB a[MAXN][MAXN]; void gaoss(int n) { int col = 1, row = 1; for (; col <= n; ++col, ++row) { int maxr = row; rep(i, row+1, n) if (fabs(a[i][col]) > fabs(a[maxr][col])) maxr = i; if (maxr != row) rep(i, col, n+1) swap(a[maxr][i],a[row][i]); rep(i, row+1, n+1) a[row][i] /= a[row][col]; a[row][col] = 1; rep(i, 1, n) if (i != row) { rep(j, col+1, n+1) a[i][j] -= a[i][col]*a[row][j]; a[i][col] = 0; } } } int ui[MAXN*MAXN], vi[MAXN*MAXN]; int du[MAXN]; DB f[MAXN*MAXN], ans; int main() { cin >> n >> m; rep(i, 1, m) { cin >> ui[i] >> vi[i]; ++du[ui[i]], ++du[vi[i]]; } rep(i, 1, m) { a[ui[i]][vi[i]] = -1.0 / du[vi[i]]; a[vi[i]][ui[i]] = -1.0 / du[ui[i]]; } rep(i, 1, n-1) a[i][i] = 1, a[i][n] = 0; a[n][n] = 0, a[1][n] = 1; gaoss(n-1); rep(i, 1, m) f[i] = a[ui[i]][n]/du[ui[i]]+a[vi[i]][n]/du[vi[i]]; sort(f+1, f+m+1); rep(i, 1, m) ans += f[i] * (m-i+1); printf("%.3f\n",ans); return 0; }