bzoj2337 XOR路径 高斯消元

       遇到位运算,还是一位一位来。假设考虑二进制第k位,那么

       令f[i]表示以到达i时,第i位存在的期望,那么对于所有与i相连的j,如果(i,j)的第k位为1,那么f[i]+=(1-f[j])/i的入度,否则f[i]+=f[j]/i的入度。

       这样看起来有n个方程,但是有一个是没用的,随便去掉一个。然后实际上令从n到1是等价的,只需要让f[n]=0即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define eps 1e-10
#define N 105
#define M 20005
using namespace std;

int n,m,tot,bin[35],etr[N],fst[N],pnt[M],len[M],nxt[M];
double a[N][N];
void add(int x,int y,int z){
	etr[y]++; pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot;
}
void gas(){
	int i,j,k;
	for (i=1; i<=n; i++){
		for (j=i; j<=n; j++) if (a[j][i]) break;
		if (j>n) continue; if (i!=j) swap(a[i],a[j]);
		for (k=i+1; k<=n; k++)
			if (fabs(a[k][i])>eps){
				double x=a[k][i]/a[i][i];
				for (j=n+1; j>=i; j--)	a[k][j]-=x*a[i][j];
			}
	}
	for (i=n; i; i--){
		for (j=i+1; j<=n; j++) a[i][n+1]-=a[i][j]*a[j][n+1];
		a[i][n+1]/=a[i][i];
	}
}
int main(){
	scanf("%d%d",&n,&m); int i,x,p,mx=0;
	for (i=1; i<=m; i++){
		int x,y,z; scanf("%d%d%d",&x,&y,&z);
		add(x,y,z); if (x!=y) add(y,x,z);
		mx=max(mx,z);
	}
	bin[0]=1; for (i=1; i<=30; i++) bin[i]=bin[i-1]<<1;
	double ans=0;
	for (i=0; bin[i]<=mx; i++){
		memset(a,0,sizeof(a));
		for (x=1; x<=n; x++){
			a[x][x]=1;
			for (p=fst[x]; p; p=nxt[p]){
				int y=pnt[p];
				if (len[p]&bin[i]){ a[x][y]+=1.0/etr[x]; a[x][n+1]+=1.0/etr[x]; }
				else a[x][y]-=1.0/etr[x];
			}
		}
		for (x=1; x<=n+1; x++) a[n][x]=0; a[n][n]=1;
		gas(); ans+=a[1][n+1]*bin[i];
	}
	printf("%.3f\n",ans);
	return 0;
}


by lych

2016.3.7

你可能感兴趣的:(异或,高斯消元,期望)