267C
二分+高斯消元
我们利用物理里的势能来表示,每个点有一个势能h,再由流量守恒可以得到deg[x]*h[x]=sigma(h[y]) 如果x,y之间有边。这个式子是由流量守恒推出的,所以当x=1或n是不满足这个方程的。
每次二分n的势能,然后把1和n赋值,高斯消元,检验答案。
势能保证了到达一个点所有路径长度相同,也保证了流量守恒。
各种小错误 调了两个小时
#include<bits/stdc++.h> using namespace std; const int N = 110; struct edge { int a, b; double c; } e[N * 100]; int n, m; double ans; double a[N][N]; void gauss() { for(int i = 1; i <= n; ++i) { int now = i, pos = i; while(now <= n) { if(fabs(a[now][i]) > fabs(a[pos][i])) pos = now; ++now; } for(int j = 1; j <= n + 1; ++j) swap(a[i][j], a[pos][j]); if(fabs(a[i][i]) < 1e-10) continue; double x = a[i][i]; for(int j = 1; j <= n + 1; ++j) a[i][j] /= x; for(int j = 1; j <= n; ++j) if(j != i && fabs(a[j][i]) > 1e-10) { double x = a[j][i] / a[i][i]; for(int k = 1; k <= n + 1; ++k) a[j][k] -= x * a[i][k]; } } } bool C(double x) { for(int i = 1; i <= n; ++i) for(int j = 1; j <= n + 1; ++j) a[i][j] = 0.0; for(int i = 1; i <= m; ++i) { if(e[i].b != 1 && e[i].b != n) { a[e[i].b][e[i].b] += 1.0; a[e[i].b][e[i].a] -= 1.0; } if(e[i].a != 1 && e[i].a != n) { a[e[i].a][e[i].a] += 1.0; a[e[i].a][e[i].b] -= 1.0; } } a[1][1] = 1.0; a[n][n] = 1.0; a[n][n + 1] = x; gauss(); for(int i = 1; i <= m; ++i) { if(fabs(a[e[i].b][n + 1] - a[e[i].a][n + 1]) > e[i].c) return false; } return true; } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= m; ++i) { scanf("%d%d%lf", &e[i].a, &e[i].b, &e[i].c); } double l = 0, r = 1e9 + 1; while(r - l > 1e-10) { double mid = (l + r) / 2.0; if(C(mid)) l = ans = mid; else r = mid; } C(ans); ans = 0; for(int i = 1; i <= m; ++i) { if(e[i].b == n || e[i].a == n) ans += fabs(a[e[i].b][n + 1] - a[e[i].a][n + 1]); } printf("%.6f\n", ans); for(int i = 1; i <= m; ++i) printf("%.6f\n", a[e[i].b][n + 1] - a[e[i].a][n + 1]); return 0; }