蓝书(算法竞赛进阶指南)刷题记录——BZOJ2337 【HNOI2011】XOR和路径(概率期望+DP+高斯消元)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/91457722

题目:BZOJ2337.
题目大意:给定一张 n n 个点 m m 条边的带边权无向连通图,求从点 1 1 到点 n n 的异或和的期望.
1 n 100 , 1 m 1 0 4 1\leq n\leq 100,1\leq m\leq 10^4 ,边权 [ 0 , 1 0 9 ] \in[0,10^9] .

看到位运算先想到拆位,显然每一位互不影响.

假设现在考虑某一位,我们设 f [ i ] f[i] 表示这一位从点 i i 出发到点 n n 异或和为 1 1 的概率.

d e g [ i ] deg[i] 表示点 i i 的度,容易列出方程:
f [ x ] = ( x , y ) E 1 d e g [ x ] { f [ y ] v ( x , y ) = 0 1 f [ y ] v ( x , y ) = 1 f[x]=\sum_{(x,y)\in E}\frac{1}{deg[x]}* \left\{\begin{matrix} f[y]&v(x,y)=0\\ 1-f[y]&v(x,y)=1 \end{matrix}\right.

然后我们根据这个方程高消一下即可得到最后的概率,也就可以求得期望了.

时间复杂度 O ( n 3 log 1 0 9 ) O(n^3\log 10^9) .

注意自环不能加两次,只能当一条有向边算.

代码如下:

#include<bits/stdc++.h> 
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=100,M=10000,C=30;
const double eps=1e-8;

int n,m;
struct side{
  int y,next,v;
}e[M*2+9];
int lin[N+9],cs;

void Ins(int x,int y,int v){e[++cs].y=y;e[cs].v=v;e[cs].next=lin[x];lin[x]=cs;}

int deg[N+9];
double ans,mat[N+9][N+9];

void Gauss(){
  int now=1;
  for (int i=1;i<n;++i){
    int r=now;
    for (int j=now+1;j<n;++j)
      if (abs(mat[j][i])>abs(mat[r][i])) r=j;
    if (abs(mat[r][i])<eps) continue;
    if (r^now) swap(mat[r],mat[now]);
    double t=mat[now][i];
    for (int j=1;j<=n;++j) mat[now][j]/=t;
    for (int j=1;j<n;++j)
      if (j^now){
        t=mat[j][i];
        for (int k=1;k<=n;++k) mat[j][k]-=t*mat[now][k];
	  }
	++now;
  }
  for (int i=1;i<n;++i) mat[i][n]/=mat[i][i]; 
}

Abigail into(){
  scanf("%d%d",&n,&m);
  int x,y,v;
  for (int i=1;i<=m;++i){
  	scanf("%d%d%d",&x,&y,&v);
  	Ins(x,y,v);++deg[x];
  	if (x^y) Ins(y,x,v),++deg[y];
  }
}

Abigail work(){
  for (int i=0;i<=C;++i){
    for (int j=1;j<n;++j)
      for (int k=1;k<=n;++k)
        mat[j][k]=0;
    for (int j=1;j<n;++j){
	  mat[j][j]-=1.0;
	  for (int k=lin[j];k;k=e[k].next)
	    if (e[k].y==n) mat[j][n]-=1.0*(e[k].v>>i&1)/deg[j];
	    else if (e[k].v>>i&1) mat[j][e[k].y]-=1.0/deg[j],mat[j][n]-=1.0/deg[j];
	      else mat[j][e[k].y]+=1.0/deg[j];
	}
    Gauss();
    ans+=mat[1][n]*(1<<i);
  }
}

Abigail outo(){
  printf("%.3lf\n",ans);
}

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

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/91457722