[HNOI 2011] XOR和路径

[题目链接]

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

[算法]

        直接进行计算显然是不可做的,我们考虑按位计算答案

        从低位向高位枚举,此时问题就转化为了 : 在一个联通无向图中,从1出发走到n,路径异或和为1的概率是多少

        用f[i]表示从i到n路径异或和为1的概率,有状态转移方程 :

        f[i] = sigma( f[j] / degree[i] ) ( w(i,j) = 0 ) + sigma( (1 - f[j]) / degree[i] ) ( w(i,j) = 1)

        由于图中可能存在自环和重边,我们无法确定枚举状态的顺序,因此,需要使用高斯消元

[代码]

        

#include<bits/stdc++.h>
using namespace std;
#define MAXN 110
#define MAXM 10010
#define MAXLOG 31

int i,k,u,v,w,n,m,tot;
int head[MAXN],degree[MAXN];
double a[MAXN][MAXN];
double ans;

struct Edge
{
        int to,w,nxt;
} e[MAXM << 1];
inline void addedge(int u,int v,int w)
{
        tot++;
        e[tot] = (Edge){v,w,head[u]};
        head[u]    = tot;    
}  
inline void gauss()
{
        int i,j,k,p;
        double rate;
        for (i = 1; i <= n; i++)
        {
                p = i;
                for (j = i + 1; j <= n; j++)
                {
                        if (fabs(a[j][i]) > fabs(a[p][i]))
                                p = j;         
                }
                for (j = 1; j <= n + 1; j++) swap(a[i][j],a[p][j]);
                for (j = 1; j <= n; j++)
                {
                        if (i == j) continue;
                        rate = a[j][i] / a[i][i];
                        for (k = i; k <= n + 1; k++) a[j][k] -= a[i][k] * rate;
                }            
        } 
}

int main() 
{
        
        scanf("%d%d",&n,&m);
        for (i = 1; i <= m; i++)
        {
                scanf("%d%d%d",&u,&v,&w);
                if (u ^ v)
                {
                        addedge(u,v,w);
                        addedge(v,u,w);
                        degree[u]++; degree[v]++;
                } else
                {
                        addedge(u,v,w);
                        degree[u]++;
                }
        }
        for (i = 0; i < MAXLOG; i++)
        {
                for (u = 1; u <= n; u++)
                {
                        for (v = 1; v <= n + 1; v++)
                        {
                                a[u][v] = 0.0;
                        }
                }
                for (u = 1; u < n; u++)
                {
                        for (k = head[u]; k; k = e[k].nxt)
                        {
                                v = e[k].to;
                                if (e[k].w & (1 << i))
                                {
                                        a[u][v] -= 1.0 / degree[u];
                                        a[u][n + 1] -= 1.0 / degree[u];        
                                } else a[u][v] += 1.0 / degree[u];
                        }    
                        a[u][u] -= 1.0;
                }
                a[n][n] = 1.0;
                gauss();
                ans += 1.0 * a[1][n + 1] / a[1][1] * (1 << i);
        }
        printf("%.3lf\n",ans);
        
        return 0;
    
}

猜你喜欢

转载自www.cnblogs.com/evenbao/p/9354996.html
今日推荐