zoukankan      html  css  js  c++  java
  • 【bzoj2337】[HNOI2011]XOR和路径 期望dp+高斯消元

    题目描述


    题解

    期望dp+高斯消元

    直接求总体的期望异或和比较困难,我们可以考虑按位拆分一下,这样每一位就只有0/1两种选择。

    设f[i]表示从i到n的期望异或和,那么$f[y]=sumlimits_{exist x1 o y=0}frac{f[x1]}{d[x1]}+sumlimits_{exist x2 o y=1}frac{1-f[x2]}{d[x2]}$,其中x1->y=0表示x1到y有权值为0的边,x2->y=1表示x2到y有权值为1的边。

    这里和 bzoj3143 的处理类似,同样需要特殊处理n,令f[n]=0。

    不过这道题最恶心之处在于它有重边和自环,对于重边需要把"="变为"+=",对于自环,按照样例的意思应该是把自环边的度数看作1而不是2处理(两种方式走自环算一种)

    然后使用高斯消元求解,将f[1]乘上拆分的位加到答案中。

    时间复杂度$O(n^3log n)$

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #define N 110
    #define M 20010
    using namespace std;
    int n , m , head[N] , to[M] , len[M] , next[M] , cnt , d[N] , x[M] , y[M] , z[M];
    double a[N][N];
    double cal(int t)
    {
    	int i , j , k;
    	double f;
    	memset(a , 0 , sizeof(a));
    	for(i = 1 ; i <= m ; i ++ )
    	{
    		if(z[i] & t)
    		{
    			a[x[i]][y[i]] += 1 , a[x[i]][n + 1] += 1;
    			if(x[i] != y[i]) a[y[i]][x[i]] += 1 , a[y[i]][n + 1] += 1;
    		}
    		else
    		{
    			a[x[i]][y[i]] -= 1;
    			if(x[i] != y[i]) a[y[i]][x[i]] -= 1;
    		}
    	}
    	for(i = 1 ; i <= n + 1 ; i ++ ) a[n][i] = 0;
    	for(i = 1 ; i <= n ; i ++ ) a[i][i] += d[i];
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		for(k = i , j = i + 1 ; j <= n ; j ++ )
    			if(fabs(a[j][i]) > fabs(a[k][i]))
    				k = j;
    		for(j = i ; j <= n + 1 ; j ++ ) swap(a[k][j] , a[i][j]);
    		for(j = i + 1 ; j <= n ; j ++ )
    			for(f = a[j][i] / a[i][i] , k = i ; k <= n + 1 ; k ++ )
    				a[j][k] -= a[i][k] * f;
    	}
    	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];
    	}
    	return a[1][n + 1];
    }
    int main()
    {
    	int i;
    	double ans = 0;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= m ; i ++ )
    	{
    		scanf("%d%d%d" , &x[i] , &y[i] , &z[i]) , d[x[i]] ++ ;
    		if(x[i] != y[i]) d[y[i]] ++ ;
    	}
    	for(i = 1 << 30 ; i ; i >>= 1) ans += cal(i) * i;
    	printf("%.3lf
    " , ans);
    	return 0;
    }
    
  • 相关阅读:
    .Net Micro Framework中文讨论组
    .Net Micro Framework 4.0正式开源
    php论坛学习的一个遍历的问题(学习) 简单
    Visual C++ 2008入门经典 第十章标准模板库(二) 简单
    PHP类型转换&&类型强制转换 简单
    Visual C++ 2008入门经典 第九章练习题 简单
    Visual C++ 2008入门经典 第十章标准模板库 简单
    PHP服务端推送技术Long Polling 简单
    Visual C++ 2008入门经典 第九章类的继承和虚函数(三) 简单
    正则表达式学习一 简单
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7056128.html
Copyright © 2011-2022 走看看