ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P3211 [HNOI2011]XOR和路径 (拆位+高斯消元)

2021-04-28 20:33:58  阅读:175  来源: 互联网

标签:XOR fu int 路径 HNOI2011 节点 高斯消 define


https://www.luogu.com.cn/problem/P3211

题目描述

给定一个无向连通图,其节点编号为 1 到 N,其边的权值为非负整数。试求出一条从 1 号节点到 N 号节点的路径,使得该路径上经过的边的权值的“XOR 和”最大。该路径可以重复经过某些节点或边,当一条边在路径中出现多次时,其权值在计算“XOR 和”时也要被重复计算相应多的次数。

直接求解上述问题比较困难,于是你决定使用非完美算法。具体来说,从 1 号节点开始,以相等的概率,随机选择与当前节点相关联的某条边,并沿这条边走到下一个节点,重复这个过程,直到走到 N 号节点为止,便得到一条从 1 号节点到 N 号节点的路径。显然得到每条这样的路径的概率是不同的并且每条这样的路径的“XOR 和”也不一样。现在请你求出该算法得到的路径的“XOR 和”的期望值。

输入格式

输入文件的第一行是用空格隔开的两个正整数N和M,分别表示该图的节点数和边数。紧接着的M行,每行是用空格隔开的三个非负整数u,v和w(1≤u,v≤N,0≤w≤10^9),表示该图的一条边(u,v),其权值为w。输入的数据保证图连通。

输出格式

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

输入输出样例

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

说明/提示

样例解释:有1/2的概率直接从1号节点走到2号节点,该路径的“XOR和”为3;有1/4的概率从1号节点走一次1号节点的自环后走到2号节点,该路径的“XOR和”为1;有1/8的概率从1号节点走两次1号节点的自环后走到2号节点,该路径的“XOR和”为3…依此类推,可知“XOR和”的期望值为:3/2+1/4+3/8+1/16+3/32+…=7/3,约等于2.333。

30%的数据满足N≤30
100%的数据满足2≤N≤100,M≤10000,但是图中可能有重边或自环。

 

解:求异或和,考虑拆位,每一位只有0和1,所以拆位之后异或的结果也是只有0和1。结果只有0或1就好搞了。设f[u]表示考虑当前二进制位上u->n路径的异或和为1的期望,f[1]就是1->n路径异或和的期望,最后结果就是Σ 2i * f[1]。

对所有(u,v)€E,f[u]=1/deg[u] * (∑w(u,v)=0f[v]+∑w(u,v)=1(1-f[v]) )这个式子其实很明显,因为从u到v,边权为0不会改变异或和,而边权为1会改变。

移项后得到 deg[u] * f[u] - ∑w(u,v)=0f[v] + ∑w(u,v)=1f[v] = ∑w(u,v)=11。就可以列出n个方程组。

因为f[n] = 0;所以不需要管第n行。高斯消元然后对每一位贡献求和就是答案。

#include<bits/stdc++.h>
#define sd(x) scanf("%d",&x)
#define lsd(x) scanf("%lld",&x)
#define sf(x) scanf("%lf",&x)
#define ms(x,y) memset(x,y,sizeof x)
#define fu(i,a,b) for(register int i=a;i<=b;i++)
#define fd(i,a,b) for(register int i=a;i>=b;i--)
#define all(a) a.begin(),a.end()
#define range(a,x,y) a+x,a+y+x
#define dbug printf("bbbk\n")
#define R register
using namespace std;
using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> P;
const int N=1e5+99;
const int MN=1e7+9;
const ll mod=1e4+7;
const int MAX=1e9;
const ll INF=1e9+7;
int n,m;
int d[109];
vector<P> w[109];
double a[109][109];
double eps=1e-10;
double guass()
{
    int now=1;
    fu(i,1,n)
    {
        int p=now;
        fu(j,now+1,n)
        {
            if(fabs(a[j][i])>fabs(a[p][i])) p=j;
        }
        if(fabs(a[p][i])<=eps) continue;
        swap(a[now],a[p]);
        fu(j,1,n)
        {
            if(j==now) continue;
            if(fabs(a[j][i])<eps) continue;
            double rate=a[j][i]/a[now][i];
            fu(k,i,n+1) a[j][k]-=a[now][k]*rate;
        }
        now++;
    }
    return a[1][n+1]/a[1][1];
}
int main()
{
    cin>>n>>m;
    int mxk=0;
    fu(i,1,m)
    {
        int u,v,weight;cin>>u>>v>>weight;
        if(u==v) 
        {
            d[u]++;//自环
            w[u].push_back(P(u,weight));
        }
        else 
        {
            d[u]++,d[v]++;
            w[u].push_back(P(v,weight));
            w[v].push_back(P(u,weight));
        }
    }
    double ans=0;
    fu(st,0,30)//二进制位数
    {
        ms(a,0);
        fu(i,1,n-1)//f[n]=0,所以跳过n行
        {
            a[i][i]=d[i];
            for(P p:w[i])
            {
                int j=p.first,wt=p.second;
                if((wt>>st)&1) a[i][j]++,a[i][n+1]++;
                else a[i][j]--;
            }
        }
        ans+=guass()*(1<<st);
    }
    printf("%.3f\n",ans);
    return 0;
}

 

标签:XOR,fu,int,路径,HNOI2011,节点,高斯消,define
来源: https://www.cnblogs.com/studyshare777/p/14715617.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有