首页 > 代码库 > xor和路径(codevs 2412)

xor和路径(codevs 2412)

题目描述 Description

给定一个无向连通图,其节点编号为1到N,其边的权值为非负整数。试求出一条从1号节点到 N 号节点的路径,使得该路径上经过的边的权值的“XOR 和”最大。该路径可以重复经过某些节点或边,当一条边在路径中出现多次时,其权值在计算“XOR 和”时也要被重复计算相应多的次数。

直接求解上述问题比较困难,于是你决定使用非完美算法。具体来说,从1号节点开始,以相等的概率,随机选择与当前节点相关联的某条边,并沿这条边走到下一个节点,重复这个过程,直到走到N号节点为止,便得到一条从1号节点到N号节点的路径。显然得到每条这样的路径的概率是不同的并且每条这样的路径的“XOR 和”也不一样。现在请你求出该算法得到的路径的“XOR和”的期望值。 

输入描述 Input Description

第一行是用空格隔开的两个正整数N和M,分别表示该图的节点数和边数。紧接着的M行,每行是用空格隔开的三个非负整数u,v和w(1≤u,v≤N, 0≤w≤109),表示该图的一条边(u,v),其权值为w。输入的数据保证图连通,30%的数据满足N≤30,100%的数据满足2≤N≤100,M≤10000,但是图中可能有重边或自环。 

输出描述 Output Description

仅包含一个实数,表示上述算法得到的路径的“XOR和”的期望值,要求保留三位小数。(建议使用精度较高的数据类型进行计算) 

样例输入 Sample Input

2 2
1 1 2
1 2 3

样例输出 Sample Output

2.333

数据范围及提示 Data Size & Hint

样例解释:有1/2的概率直接从1号节点走到2号节点,该路径的“XOR和”为3;有1/4的概率从1号节点走一次1号节点的自环后走到2号节点,该路径的“XOR和”为1;有1/8的概率从1号节点走两次1号节点的自环后走到2号节点,该路径的“XOR和”为3;......;依此类推,可知“XOR和”的期望值为:3/2+1/4+3/8+1/16+3/32+....=7/3,约等于2.333。

数据范围如题

/*
    对于异或的题目,一般是按位拆分,设f[x]为从x到n的异或期望。 
    f[x]=Σ(1/d[x])*f[y](边权为0)+Σ(1/d[x])*(1-f[y])(边权为1)
    将上式变形得到:
    f[x]-Σ(1/d[x])*f[y](边权为0)+Σ(1/d[x])*f[y](边权为1)=Σ (1/d[x])(边权为1)
    然后高斯消元。 
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define N 110
#define M 10010
#define ld long double
using namespace std;
int head[N],d[N],cnt,n,m;
ld a[N][N],ans;
struct node{int v,w,pre;}e[M*2];
void add(int u,int v,int w){
    e[++cnt].v=v;e[cnt].w=w;e[cnt].pre=head[u];head[u]=cnt;
}
void gauss(){
    for(int i=1;i<=n;i++){
        int id=i;ld maxn=fabs(a[i][i]);
        for(int j=i+1;j<=n;j++) if(fabs(a[j][i])>maxn) id=j,fabs(a[j][i]);
        if(id!=i) swap(a[i],a[id]);
        ld t=a[i][i];
        for(int j=1;j<=n+1;j++) a[i][j]/=t;
        for(int j=1;j<=n;j++)
            if(j!=i){
                ld t=a[j][i];
                for(int k=1;k<=n+1;k++)
                    a[j][k]-=t*a[i][k];
            }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);add(u,v,w);d[u]++;
        if(u!=v) add(v,u,w),d[v]++;
    }
    for(int t=0;t<=30;t++){
        memset(a,0,sizeof(a));
        for(int i=1;i<n;i++){
            a[i][i]=1.0;
            for(int j=head[i];j;j=e[j].pre){
                if(e[j].w&(1<<t)) a[i][e[j].v]+=1.0/d[i],a[i][n+1]+=1.0/d[i];
                else a[i][e[j].v]-=1.0/d[i];
            }
        }
        a[n][n]=1.0;gauss();ans+=a[1][n+1]*(1<<t);
    }
    printf("%.3lf",(double)ans);
    return 0;
}

 

xor和路径(codevs 2412)