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;
}
posted @ 2022-10-15 17:24  qingyanng  阅读(11)  评论(0编辑  收藏  举报