[COGS] [wc2011]Xor

2 篇文章 0 订阅
1 篇文章 0 订阅

题目描述

给定一个n(n≤50000) 个点m(m≤10000) 条边的无向图,每条边上有一个权值。请你求一条从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
Xor

题解

首先在dfs中随意的选择一条合法路径并且记录异或和
我们可以发现 如果一个环和当前的路径有公共的边的话 我们可以异或一整个环来改变路径, 并且可以发现若果走一个环的话,一定要走完一整个环,不可能走一半
如果有一个环和当前没有公共边的话,如果xor整个环的值优的话,可以直接选不用考虑能不能走到 因为可以直接从1走到环,绕一圈,再回来,在走到当前路径,相当于只异或整个环的异或值

方法

找出所有的环,记录xor和 然后筛线性基 最后贪心的选择。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=100000+10;
int n,m;
struct node
{
    int v,w,next;
}tb[maxn];
int len,h[maxn],f[maxn];
long long a[maxn],ans,dis[maxn];
bool used[maxn],flag,visit[maxn];
void add1(int i,int j,int w)
{
    len++; tb[len].v=j; tb[len].next=h[i]; tb[len].w=w; h[i]=len;
}
void dfs(int x,long xorsum,int last)
{
    if(x==n) flag=true;
    if(used[x])
    {
        a[++a[0]]=xorsum^f[x]; return;
    }
    used[x]=true; f[x]=xorsum;
    for(int i=h[x]; i ; i=tb[i].next)
    {
        int v=tb[i].v;
        if(v!=last)
        {
            if(!flag)
            {
//              cout<<x<<' ';
                dis[v]=dis[x]^tb[i].w;
            }
            dfs(v,xorsum^tb[i].w,x);
        }
    }
//  used[x]=false;
}
int main()
{
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    scanf("%d %d",&n,&m);
    for(int i=1; i<=m; i++)
    {
        int x,y,w;
        scanf("%d %d %d",&x,&y,&w);
        add1(x,y,w); add1(y,x,w);
    }
    a[0]=0;
    dfs(1,0,0);
    long long tmp=1,max1=0;
    for(int i=1; i<a[0]; i++)
    {
        max1=max(max1,a[i]);    
    }
    while((tmp<<1)<=max1)
        tmp<<=1;
    ans=dis[n];
    while(tmp)
    {
        int p=-1;
        for(int i=1;i<=a[0]; i++)
        {
            if(a[i]&tmp)
            {
                p=i; break;
            }
        }
        if(p!=-1)
        {
            for(int i=p+1; i<=a[0]; i++)
            {
                if(a[i]&tmp)
                {
                    a[i]^=a[p];
                }
            }
            if(!(ans&tmp))
            {
                ans^=a[p];
//              cout<<p<<endl;
            }
            a[p]=0;
        }
        tmp>>=1;
    }
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值