• [HNOI2011] XOR和路径


    Description

    给定一个(N(Nleq 100))个点的无向连通图,边有边权。行动的规则是随机选择与当前点相连的一条边,移动到这条边的另一个顶点。求从(1)(n)的经过的路径上边权的期望(XOR)和。

    Solution

    跟两年后的‘游走’挺像的?这大概是一类套路?

    显然的状态是(f[i])表示从(i)(n)的期望(XOR)和。

    跟那个题不一样的是这里是求(XOR)和,因为它有重边不是很容易高斯消元,我们考虑拆位算这个东西。

    拆了位问题就很简单了。假设当前位数为(bit)

    枚举(i)的出边,设另一个顶点是(j)。如果这条边的边权的(bit)位是(1),那么(f[i]+=(1-f[j])),否则(f[i]+=f[j]) 。这样资瓷合并,高斯消元套上去就完事了。

    Code

    #include<set>
    #include<map>
    #include<cmath>
    #include<queue>
    #include<cctype>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using std::min;
    using std::max;
    using std::swap;
    using std::vector;
    const int N=105;
    typedef double db;
    typedef long long ll;
    #define pb(A) push_back(A)
    #define pii std::pair<int,int>
    #define all(A) A.begin(),A.end()
    #define mp(A,B) std::make_pair(A,B)
    
    db a[N][N],f[N],ans;
    int n,m,cnt,head[N],deg[N];
    
    struct Edge{
        int to,nxt,dis;
    }edge[N*200];
    
    void add(int x,int y,int z){
        edge[++cnt].to=y;
        edge[cnt].nxt=head[x];
        edge[cnt].dis=z;
        head[x]=cnt;
    }
    
    int getint(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }
    
    db abs(db x){
        return x>0?x:-x;
    }
    
    void print(){
        for(int i=1;i<=n;i++,puts(""))
            for(int j=1;j<=n+1;j++)
                printf("%.3lf ",a[i][j]);
    }
    
    db calc(int bit){
        memset(a,0,sizeof a);memset(f,0,sizeof f);
        for(int i=1;i<n;i++){
            a[i][i]=-deg[i];
            for(int j=head[i];j;j=edge[j].nxt){
                int to=edge[j].to;
                if(to==n){
                    if(edge[j].dis>>bit&1) a[i][n]--;
                } else{
                    if(edge[j].dis>>bit&1) a[i][to]--,a[i][n]--;
                    else a[i][to]++;
                }
            }
        }
        for(int i=1;i<n;i++){
            int idx=i;
            for(int j=i+1;j<n;j++){
                if(abs(a[j][i])-abs(a[idx][i])>1e-8)
                    idx=j;
            } swap(a[i],a[idx]);
            for(int j=i+1;j<n;j++){
                db tmp=a[j][i]/a[i][i];
                for(int p=i;p<=n;p++)
                    a[j][p]-=tmp*a[i][p];
            }
        }
        for(int i=n-1;i;i--){
            for(int j=i+1;j<n;j++)
                a[i][n]-=a[i][j]*f[j];
            f[i]=a[i][n]/a[i][i];
        } return f[1];
    }
    
    signed main(){
        n=getint(),m=getint();
        for(int i=1;i<=m;i++){
            int x=getint(),y=getint(),z=getint();
            add(x,y,z);deg[x]++;
            if(x!=y) add(y,x,z),deg[y]++;
        }
        for(int i=0;i<=30;i++)
            ans+=calc(i)*(1<<i);
        printf("%.3lf
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    C# 修改DataTable列 类型 并从新赋值
    buildroot 使用小记
    如何查看linux内核的版本号?
    在ubuntu上使用华为的3G无线上网卡
    在ubuntu上编译rasbian kernel(for raspberry pi 1)
    装了ubuntu后笔记本电脑的无线网卡用不了,怎么设置?
    Ubuntu下哪个PDF阅读器更好使???
    转载 :Linux有问必答:如何在Debian或Ubuntu上安装完整的内核源码
    Raspberry Pi
    cygwin下调用make出现的奇怪现象
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/9848133.html
Copyright © 2020-2023  润新知