P3211 [HNOI2011]XOR和路径 (拆位+高斯消元)
作者:互联网
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 和”的期望值,要求保留三位小数。(建议使用精度较高的数据类型进行计算)
输入输出样例
输入 #12 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