题目描述
题目解析
首先如果直接思考那么我们不容易得到答案,那么我们换一种思路,我们先解决这个问题的弱化版本,我们考虑在无向图G中知道S和T如何去寻找最大的环路首先我们根据其中一个点(这里选择S)为根构造一棵树
那么我哦们可以容易的发现我们需要的就是包含S-T(根到T)的路径的异或值。但是当前并不是最优解,那么我们可以发现如果这个时候我们可以找到一个到达T的更优解那么这条路径必定与当前路径并联,那么并联的部分可以构成一个环,那么问题就转化成了包含S到T的路径同时找到多个环使所有的异或值最大,那么如果此时我们还需要走一次S到T那么我们的路径就变成了S−T−S−T那么我们重新考虑一下当前S到T的路径上进行扩展,我们需要找到多个环使所有环异或之后使得S到T的路径的异或值尽量的大那么我们因为贪心的考虑需要高位为1
那么我们整个问题就变成了两个问题的合集
1. 给你N个数求取出一些数的异或和最大值
2. 判断当前环路的异或值
那么我们看这一题:http://blog.csdn.net/jeremygjy/article/details/50613026 我们用方法1,2都可以解决(推荐用2)或者还有第三种,详见莫涛的PPT
对于每一个环我们发现如果每一次连接一条边,那么就会构成一个新的环,如果环中本来还有环路,那么另一部分环路可以通过异或得到,所以不用考虑另一部分。贪心的获得较高为为1之后我们看当前S到T的每一部分是否有必要进行替换,如果当前一位替换之后可能得到更优的东东,那么为什么不用呢?
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int MAXN = 50000;
const int MAXM = 200000;
struct node{
int v;
ll val;
node *next;
}Eds[MAXM*2+10], *ecnt=Eds, *adj[MAXN+10];
void addedge(int u, int v, ll t){
++ecnt;
ecnt->v = v;
ecnt->next = adj[u];
ecnt->val = t;
adj[u] = ecnt;
}
bool vis[MAXN+10];
ll sum[MAXN+10], As[MAXM+10];
void dfs(int u){
vis[u] = 1;
for(node *p=adj[u];p;p=p->next){
if(vis[p->v]){
As[++As[0]] = sum[p->v] ^ sum[u] ^ p->val;
continue;
}
sum[p->v] = sum[u] ^ p->val;
dfs(p->v);
}
}
void gauss_jordan(){
int i,row,col=59;
ll Max = 0;
for(int i=1;i<=As[0];i++)
Max = max(Max, As[i]);
for(row=1;row<=As[0]&&col>=0;row++,col--){
if(!(As[row]>>col)&1)
for(i=row+1;i<=As[0];i++)
if((As[i]>>col)&1){
swap(As[i],As[row]);
break;
}
if(!((As[row]>>col)&1)){
row--;
continue;
}
for(i=1;i<=As[0];i++)
if(i!=row&&(As[i]>>col)&1)
As[i]^=As[row];
}
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
int u, v;
long long val;
for(int i=1;i<=m;i++){
scanf("%d%d%lld", &u, &v, &val);
addedge(u, v, val);
addedge(v, u, val);
}
dfs(1);
gauss_jordan();
ll ans = sum[n];
for(int i=1;i<=As[0];i++)
ans = max(ans^As[i], ans);
printf("%lld\n", ans);
return 0;
}