P3232 [HNOI2013]游走 [高斯消元]

游走

题目描述见链接 .


\color{red}{正解部分}

题目要求走过的 编号和期望最小,

先求出 的期望值 f[i]f[i], 走过一条边 u,vu, v 的期望值即为 f[u]/du[u]+f[v]/du[v]f[u]/du[u] + f[v]/du[v], 最后将期望值大的边赋予较小的编号即可 .

现在求 的期望值, f[i]=f[to]/du[to]f[i] = \sum f[to]/du[to], 依此可以列出 NN 个方程, 高斯消元 解方程即可 .


\color{red}{实现部分}

  • NN 号点相连的 点, 边 不用计 NN 的贡献 .
  • 走到 11 的实际期望值 为解出的期望 +1+1 .
#include<bits/stdc++.h>
#define reg register

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 505;
const double eps = 1e-14;

int N;
int M;
int num0;
int du[maxn];
int head[maxn];
int u[maxn*maxn];
int v[maxn*maxn];

double B[maxn*maxn];
double A[maxn][maxn];

struct Edge{ int nxt, to; } edge[maxn*maxn<<1];

void Add(int from, int to){
        edge[++ num0] = (Edge){ head[from], to };
        head[from] = num0; du[from] ++;
}

void Guass(){
        for(reg int i = 1; i < N; i ++){
                int max_id = i;
                for(reg int j = i+1; j < N; j ++)
                        if(fabs(A[j][i]) > fabs(A[max_id][i])) max_id = j;
                std::swap(A[max_id], A[i]);
                for(reg int j = N; j >= i; j --) A[i][j] /= A[i][i];
                for(reg int j = i+1; j < N; j ++){
                        if(fabs(A[j][i]) < eps) continue ;
                        for(reg int k = N; k >= i; k --) A[j][k] -= A[j][i] * A[i][k];
                }
        }
        for(reg int i = N-1; i >= 1; i --)
                for(reg int j = i+1; j < N; j ++) A[i][N] -= A[j][N]*A[i][j];
}

int main(){
        N = read(), M = read();
        for(reg int i = 1; i <= M; i ++){
                u[i] = read(), v[i] = read();
                Add(u[i], v[i]), Add(v[i], u[i]);
        }
        for(reg int i = 1; i < N; i ++){
                A[i][i] = 1;
                for(reg int j = head[i]; j; j = edge[j].nxt){
                        int to = edge[j].to;
                        if(to == N) continue ;
                        A[i][to] = -1.0/du[to];
                }
        }
        A[1][N] = 1;
        Guass();
        for(reg int i = 1; i <= M; i ++){
                if(u[i] != N) B[i] += A[u[i]][N]/du[u[i]];
                if(v[i] != N) B[i] += A[v[i]][N]/du[v[i]];
        }
        std::sort(B+1, B+M+1);
        double Ans = 0;
        for(reg int i = 1; i <= M; i ++) Ans += B[i] * (M-i+1);
        printf("%.3lf\n", Ans);
        return 0;
}
posted @ 2019-11-01 22:45  XXX_Zbr  阅读(183)  评论(0编辑  收藏  举报