XOR和路径 高斯消元+期望

[HNOI2011]XOR和路径(https://www.cnblogs.com/beretty/p/9540612.html)

题目描述

给定一个无向连通图,其节点编号为 1 到 N,其边的权值为非负整数。试求出一条从 1 号节点到 N 号节点的路径,使得该路径上经过的边的权值的“XOR 和”最大。该路径可以重复经过某些节点或边,当一条边在路径中出现多次时,其权值在计算“XOR 和”时也要被重复计算相应多的次数。
直接求解上述问题比较困难,于是你决定使用非完美算法。具体来说,从 1 号节点开始,以相等的概率,随机选择与当前节点相关联的某条边,并沿这条边走到下一个节点,重复这个过程,直到走到 N 号节点为止,便得到一条从 1 号节点到 N 号节点的路径。显然得到每条这样的路径的概率是不同的并且每条这样的路径的“XOR 和”也不一样。现在请你求出该算法得到的路径的“XOR 和”的期望值。

输入描述:

从文件input.txt中读入数据,输入文件的第一行是用空格隔开的两个正整数N和M,分别表示该图的节点数和边数。
紧接着的M行,每行是用空格隔开的三个非负整数u,v和w(1≤u,v≤N,0≤w≤109),表示该图的一条边(u,v),其权值为w。
输入的数据保证图连通,30%的数据满足N≤30,100%的数据满足2≤N≤100,M≤10000,但是图中可能有重边或自环。

输出描述:

输出文件 output.txt 仅包含一个实数,表示上述算法得到的路径的“XOR 和”的期望值,要求保留三位小数。(建议使用精度较高的数据类型进行计算)

示例1

输入
2 2
1 1 2
1 2 3
输出
2.333

思路

看起来比较常规:f[i]:i到n的期望值。
\(f[u]=\sum (f[to] 异或 w)/d[u]\)
因为可以有环,递推是不可能了。当然是上高斯消元。
但是高斯消元,不能异或。位运算我们考虑拆位。
对于每一位,我们能不能把式子变成乘。我们必须把f[i]的含义改了
f[i]:f[i]:i到n第pos位为1的概率。
如果u-v的边的pos位为1。
那么f[u]=(1-f[to])/d[u]
如果u-v的边的pos位为0。
那么f[u]=(f[to])/d[u]

#include<bits/stdc++.h>
using namespace std;

const double eps=1e-8;
const int maxn=105;
double a[maxn][maxn];

void Gauss(int n) {
    for(int i=1; i<=n; ++i) {
        int r=i;
        for(int j=i+1; j<=n; ++j) //找主元系数的绝对值最大的一行
            if(fabs(a[j][i])>fabs(a[r][i]))
                r=j;
        if(fabs(a[r][i])<eps) {  //最大为0,无解
            printf("No Solution\n");
            return;
        }
        if(r!=i)
            for(int j=1; j<=n+1; ++j)
                swap(a[i][j],a[r][j]);
        for(int j=1; j<=n; ++j)  //消元
            if(j!=i) {
                double tmp=a[j][i]/a[i][i];
                for(int k=i; k<=n+1; ++k)
                    a[j][k]-=a[i][k]*tmp;
            }
    }
//    for(int i=1; i<=n; ++i)
//        printf("%.2f\n",a[i][n+1]/a[i][i]);
}

struct Edge {
    int to, w;
};
vector<Edge> G[105];

int main() {

    int n, m; scanf("%d%d",&n, &m);
    for(int i=1; i<=m; i++) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        G[a].push_back({b, c});
        if(a!=b){
            G[b].push_back({a, c});
        }
    }
    double ans=0;
    for(int pos=0; pos<=31; pos++) {
        memset(a, 0, sizeof(a));
        a[n][n]=1;
        for(int u=1; u<n; u++) {
            int sz=G[u].size();
            a[u][u]=1;
            for(auto x: G[u]) {
                int to=x.to, w=x.w;
                if((w&(1<<pos))) {
                    a[u][to]+=1.0/sz;
                    a[u][n+1]+=1.0/sz;
                } else {
                    a[u][to]-=1.0/sz;
                }
            }
        }
        Gauss(n);
        ans+=(1<<pos)*a[1][n+1]/a[1][1];
    }
    printf("%.3f\n", ans);

    return 0;
}

上一篇:cf 888G - Xor-MST(01字典树+分治)


下一篇:env (arcpy)