[BZOJ 2337][HNOI2011]XOR和路径

http://www.lydsy.com/JudgeOnline/problem.php?id=2337

高斯消元解期望方程。
按位考虑
首先从n出来的边不能算!
然后期望要倒着推
因为我们不知道1到n的期望但是我们知道n到n的期望
并且 xor 的期望 1
则有 if(dis==0)E(u)=E(v)/deg[u]
elseE(u)=(1E(v))/deg[u]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 100010
using namespace std;

int n, m;

struct Edge{int u, v, dis;};

Edge edge[maxn], G[maxn];

int cnt, deg[maxn];

void add(int u, int v, int w){
    cnt ++;
    edge[cnt].v = v;
    edge[cnt].u = u;
    edge[cnt].dis = w;
    deg[u] ++;
}

double a[110][110];


void Gauss(int n){
    for(int i = 1; i <= n; i ++){
        for(int j = i; j <= n; j ++){
            if(a[j][i]){
                for(int k = 1; k <= n+1; k ++)
                    swap(a[i][k], a[j][k]);
                for(int k = 1; k <= n+1; k ++)
                    if(k != i)a[i][k] /= a[i][i];
                a[i][i] = 1;
                break;
            }
        }
        if(a[i][i] == 0)continue;
        for(int j = 1; j <= n; j ++){
            if(j == i || a[j][i] == 0)continue;
            double t = a[j][i];
            for(int k = i; k <= n+1; k ++)
                a[j][k] -= t * a[i][k];
        }
    }
}

void Debug(int n){
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= n+1; j ++)
            printf("%.2lf ", a[i][j]);
        printf("\n");
    }puts("");
}

double solve(int p){
    memset(a, 0, sizeof a);

    /*
       if(dis == 1)E(u) = E(v) * 1/deg[u]
       else E(u) = (1 - E(v)) * 1/deg[u]
    */
    for(int i = 1; i <= n; i ++)a[i][i] = 1;
    for(int i = 1; i <= cnt; i ++){
        int u = edge[i].u, v = edge[i].v;
        if(u == n)continue;
        if(edge[i].dis >> p & 1){
            a[u][v] += 1.0 / deg[u];
            a[u][n+1] += 1.0 / deg[u];
        }
        else a[u][v] -= 1.0 / deg[u];
    }

    Gauss(n);
    return a[1][n+1];
}

int main(){
    scanf("%d%d", &n, &m);
    int u, v, w;
    for(int i = 1; i <= m; i ++){
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w);
        if(v != u)add(v, u, w);
    }
    double ans = 0;
    for(int i = 30; i >= 0; i --)
        ans += solve(i) * (1 << i);
    printf("%.3lf\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值