异或值 xor

题目描述

给出一个 N 个点的带权无向图,要求从 1 号点到 N 号点的一条路径,使得路径上的边 权异或值最大.

输入格式

第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。

接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。

 

输出格式

仅包含一个整数,表示最大的XOR和(十进制结果) 。

 

样例

样例输入

5 7
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2

样例输出

6

数据范围与提示

【题目来源】

WC2011


solution

 

如果没有环,那么方案是确定的。
对于每一个环我们都可以选择走或不走。
那么这就是一个线性基的问题了。
 
稍稍回忆一下线性基。
问题:给一个集合,求异或和最大的一个子集。
我们考虑一个60位的数组。
现在一个个往里加数。
枚举这个数从高位到低位的所有1,如果线性基这一位为0,那么就加入,然后break;
否则异或上这位上的数继续取。
这样子原集合中能异或出的所有数新集合中也能异或出来。
然后从高位到低位贪心即可。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100005
#define ll long long 
using namespace std;
int n,m,head[maxn],tot=1,top;
ll t3,c[maxn*5],d[maxn],b[63];
bool vis[maxn];
struct node{
    int v,nex;
    ll w;
}e[maxn*2];
void lj(int t1,int t2,ll t3){
    e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs(int k,ll v){
    vis[k]=1;d[k]=v;
    
    for(int i=head[k];i;i=e[i].nex){
        if(!vis[e[i].v]){
            dfs(e[i].v,v^e[i].w);
        }
        else c[++top]=v^d[e[i].v]^e[i].w;
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1,t1,t2;i<=m;i++){
        scanf("%d%d%lld",&t1,&t2,&t3);
        lj(t1,t2,t3);lj(t2,t1,t3);
    }
    dfs(1,0);
    
    for(int i=1;i<=top;i++){
        for(int j=62;j>=0;j--){
            if(c[i]&(1LL<<j)){
                if(!b[j]){b[j]=c[i];break;}
                else c[i]^=b[j];
            }
        }
    }
    ll ans=d[n];
    for(int i=62;i>=0;i--){
        ans=max(ans,ans^b[i]);
    }
    cout<<ans<<endl;
    return 0;
}
View Code

 

posted @ 2019-02-22 14:27  liankewei123456  阅读(298)  评论(0编辑  收藏  举报