bzoj 2337: [HNOI2011]XOR和路径

Description

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

solution

正解:高斯消元
根据期望的线性性,要求的东西可以拆成每一位二进制位的期望之和
考虑从i到达n时该二进制位为1的方案,分边权是否为1讨论:
(f[j]+=f[i]/du[i]) 如果边权该位为0
(f[j]+=(1-f[i])/du[i]) 如果边权的该位为1
考虑到这是有向图,且存在环,所以不能拓扑序DP,用高斯消元可以解:
我们把 f[1],f[2]...f[n]看做是变量,然后du[i]看做是系数,就可以求了
但是做出来是WA的?一看题解仿佛必须要逆向推啊?原因仿佛是正推会存在不能走到i的概率?

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=105,M=20005;
int n,m,num=0,du[N],head[M],to[M],dis[M],nxt[M];
void link(int x,int y,int z){
	nxt[++num]=head[x];to[num]=y;head[x]=num;dis[num]=z;}
double a[N][N],ans=0;
inline double solve(){
	for(int l=1;l<=n;l++){
		int maxid=l;
		for(int i=l+1;i<=n;i++)
			if(fabs(a[i][l])>fabs(a[maxid][l]))maxid=l;
		if(l!=maxid)swap(a[l],a[maxid]);
		for(int i=l+1;i<=n;i++){
			if(!a[i][l])continue;
			double tmp=a[l][l]/a[i][l];
			for(int j=l;j<=n+1;j++)
				a[i][j]=a[l][j]-tmp*a[i][j];
		}
	}
	for(int i=n;i>=1;i--){
		for(int j=i+1;j<=n;j++)
			a[i][n+1]-=a[i][j]*a[j][n+1];
		a[i][n+1]/=a[i][i];
	}
	return a[1][n+1];
}
void work()
{
	int x,y,z;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		link(x,y,z);du[y]++;
		if(x!=y)link(y,x,z),du[x]++;
	}
	for(int w=0;w<=30;w++){
		memset(a,0,sizeof(a));
		for(int i=1;i<n;i++){
			a[i][i]=1.0;
			for(int j=head[i];j;j=nxt[j]){
				int u=to[j];
				if(dis[j]&(1<<w))
					a[i][u]+=1.0/du[i],a[i][n+1]+=1.0/du[i];
				else a[i][u]-=1.0/du[i];
			}
		}
		a[n][n]=1.0;
		ans+=solve()*(1<<w);
	}
	printf("%.3lf
",ans);
}

int main(){
	work();
	return 0;
}

原文地址:https://www.cnblogs.com/Yuzao/p/8017346.html