题目描述
给定一个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;
}