luogu P3232 [HNOI2013]游走 (期望, 高斯消元)
https://www.luogu.com.cn/problem/P3232
思路:
算出每条边的期望访问次数,将期望访问次数多的赋予小的编号。
一条边的期望访问次数 = 访问点u的期望/u的度 + 访问点v的期望/v的度 (u,v是边的两端点,u,v不能是终点n)
Eu = Ev1/dv1 + Ev2/dv2...
对除了n的每个点都有这个方程,那么可以得到这样一个n-1 * n 的增广矩阵。
将n-1个Eu放到对角线上,1节点的n行是1,因为1初始有1的期望,保证E1 + 1 = Ev1/dv1 + Ev2/dv2...
那么将增广矩阵的系数矩阵化为单位矩阵,a[i][n]对应的就是i的期望
样例:
1.000000 -0.500000 1.000000
-0.500000 1.000000 0.000000
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
//#define int long long
const int N = 5e2 + 5;
const int M = 2e5 + 5;
const ll P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double PI = acos(-1.0);
const double eps = 1e-13;
const int MATN = 102;
vector<int> ve[N];
struct node {
int u, v; double w;
} ed[M];
double a[N][N];
// a[N][N]是增广矩阵
int n, m;//矩阵的行数和列数
void debug()
{
int i, j;
for (i = 0; i < n - 1; i++)
{
for (j = 0; j < m + 1 - 1; j++)
{
printf("%-3lf ",a[i][j]);
}
cout << endl;
}
cout << endl;
}
int gauss(int n, int m){
int c, r;
for (c = 0, r = 0; c < m; c ++ )
{
int t = r;
for (int i = r; i < n; i ++ ) // 找到绝对值最大的行
if (fabs(a[i][c]) > fabs(a[t][c]))
t = i;
for (int i = 0; i <= m; i ++ ) swap(a[t][i], a[r][i]); // 将绝对值最大的行换到最顶端
for (int i = m; i >= c; i -- ) a[r][i] /= a[r][c]; // 将当前行的首位变成1
for (int i = 0; i < n; i ++ ) // 用当前行将c列下面所有的行消成0
if (fabs(a[i][c]) > eps && i != r)
for (int j = m; j >= c; j -- )
a[i][j] -= a[r][j] * a[i][c];
r ++ ;
}
return 0; // 有唯一解
}
int main() {
IOS
int em;
cin >> n >> em; m = n;
for ( int i = 1; i <= em; ++ i) {
int u, v; cin >> u >> v;
ve[u].push_back(v); ve[v].push_back(u);
ed[i].u = u, ed[i].v = v;
}
for(int i = 1; i < n; ++ i ) {
a[i - 1][i - 1] = 1;
for (auto j : ve[i]) {
if(j != n) a[i - 1][j - 1] = -1.0 / ve[j].size();
}
}
a[0][m -1] = 1;
gauss(n - 1, m - 1);
for ( int i = 1; i <= em; ++ i) {
int u = ed[i].u, v = ed[i].v;
if(v != n) ed[i].w += a[v - 1][m - 1] / ve[v].size();
if(u != n) ed[i].w += a[u - 1][m - 1] / ve[u].size();
}
sort(ed + 1, ed + 1 + em, [](node A, node B){ return A.w > B.w;});
double ans = 0;
for ( int i = 1; i <= em; ++ i) {
ans += ed[i].w * i;
}
cout<< fixed << setprecision(3) << ans << '\n';
return 0;
}