P3211:「HNOI2011」XOR和路径题解

主要思路

首先,这道题是概率和期望分开算的,进行 DP 时实质上是对概率进行 DP。考虑拆位,设\(dp_b [u]\)为从\(u \to n\)在第\(b\)位为\(1\)的概率,那么显然:

\[ dp_b[u] = \frac{1}{deg[u]}( \sum_{weight(u, v) !\& b} dp_b[v] \sum_{weight(u, v) \& b} (1 – dp_b[v]) ) \]

其中,\((1 – dp_b[v])\)为\(v\)为\(0\)的概率,最后答案消元完就是\(\sum_{i = 1} ans[i] 2^i\)。

代码

// P3211.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 110;
const double eps = 1e-8;

int n, m, head[MAX_N], current, deg[MAX_N];
double matrix[MAX_N][MAX_N], ans[MAX_N];
struct edge
{
    int to, nxt, weight;
} edges[20010];

void addpath(int src, int dst, int weight)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    edges[current].weight = weight, head[src] = current++;
}

void build_matrix(int pos)
{
    matrix[n][n] = 1;
    for (int pt = 1; pt <= n - 1; pt++)
    {
        matrix[pt][pt] = deg[pt];
        for (int i = head[pt]; i != -1; i = edges[i].nxt)
            if (edges[i].weight & pos)
                matrix[pt][edges[i].to]++, matrix[pt][n + 1]++;
            else
                matrix[pt][edges[i].to]--;
    }
}

void gauss()
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = i + 1; j <= n; j++)
            if (fabs(matrix[j][i]))
            {
                double rate = matrix[j][i] / matrix[i][i];
                for (int k = i; k <= n + 1; k++)
                    matrix[j][k] -= rate * matrix[i][k];
            }
    }
    for (int i = n; i >= 1; i--)
    {
        for (int j = i + 1; j <= n; j++)
            matrix[i][n + 1] -= matrix[i][j] * ans[j];
        ans[i] = matrix[i][n + 1] / matrix[i][i];
    }
    memset(matrix, 0, sizeof(matrix));
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    int mx = 0;
    for (int i = 1, x, y, z; i <= m; i++)
    {
        scanf("%d%d%d", &x, &y, &z);
        addpath(x, y, z), deg[x]++, mx = max(mx, z);
        if (x != y)
            addpath(y, x, z), deg[y]++;
    }
    double answer = 0;
    for (int i = 1; i <= mx; i <<= 1)
        build_matrix(i), gauss(), answer += ans[1] * i;
    printf("%.3lf", answer);
    return 0;
} // P3211.cpp

Leave a Reply

Your email address will not be published. Required fields are marked *