题意:
给定一个无向连通图包含 n 个点 和 m 条边,每条边有边权,现在让你求一条 从点 1 到 n 的路径,使得路径上的边权异或和最大。(可能有边重边和自环,任意边可以重复走,没有限制)
分析:
首先根据异或的性质,一条边 或 一个环 走偶数遍的异或和 都是 0 ,所以对于一个环,要么不走,要么只走一遍,那么可以构想出最优路径一定是一条从 1 到 n 的 链 上套着 若干环,那么我们把每个环的异或和加进线性基,用这条链的异或和去 异或 线性基找到最大值就可以了,可是这个最优解的链怎么找呢,其实只要任意找一条从 1 到 n 的链就可以了,因为若存在两条从 1 到 n 的链,则它们已经构成了一个环,无论你选择哪一条作为基链,异或上这个环都会得到另一条链的异或和,所以就不用担心最优解的正确性了。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 5E4+10;
struct L_B{
LL d[61],p[61];
int cnt;
L_B(){
memset(d,0,sizeof(d));
memset(p,0,sizeof(p));
cnt=0;
}
bool insert(LL val){
for(int i=60;i>=0;i--){
if(val&(1LL<<i)){
if(!d[i]){
d[i]=val;
break;
}
val^=d[i];
}
}
return val>0;
}
LL query(LL res){
for(int i=60;i>=0;i--)
if((res^d[i])>res)
res^=d[i];
return res;
}
}H;
int n,m;
struct node{
int to,nxt;LL w;
}e[N*4];
int head[N],tot=0;
void add(int u,int v,LL w){
e[++tot].to=v;
e[tot].w=w;
e[tot].nxt=head[u];
head[u]=tot;
}
LL dis[N];
bool vis[N];
void dfs(int u,int pre,LL res){
dis[u]=res,vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;LL w=e[i].w;
if(v==pre) continue;
if(vis[v]) H.insert(dis[u]^w^dis[v]);
else dfs(v,u,res^w);
}
}
int main()
{
H=L_B();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v; LL w;
scanf("%d%d%lld",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dfs(1,0,0LL);
printf("%lld",H.query(dis[n]));
}