题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5544
题目大意:T组数据, 给一个n个点, m条边的无向连通图, 无自环, 无重边, 求最大XOR回路。( n≤5∗104,m≤105,T≤30 )
思路:首先找出图中所有的本质不同的简单环, 可以用dfs构造生成树, 每个点保存从根出发的XOR路径值, 每次遇到返祖边则为新的简单环。 根据异或的性质, 所要找的回路可以看成是在这些简单环中任意取求异或和。 题目简化为有若干个数, 可取可不取, 求最大异或和。 用高斯消元求出一组基, 从高往低位贪心即可。
时间复杂度: O(60(n - m))
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
const int N = (int)5e4 + 10;
const int M = (int)2e5 + 10;
#define ll long long
using namespace std;
int n, m, tot;
int cnt, lst[N], nxt[M], to[M]; ll w[M];
ll f[N], g[M]; bool vis[N];
void add(int u, int v, ll c){
nxt[++ cnt] = lst[u]; lst[u] = cnt; to[cnt] = v; w[cnt] = c;
nxt[++ cnt] = lst[v]; lst[v] = cnt; to[cnt] = u; w[cnt] = c;
}
void dfs(int u, int pre){
vis[u] = 1;
for (int j = lst[u]; j; j = nxt[j]){
int v = to[j];
if (v == pre) continue;
if (!vis[v]) f[v] = f[u] ^ w[j], dfs(v, u);
else{
g[++ tot] = f[u] ^ f[v] ^ w[j];
}
}
}
int main(){
int T; scanf("%d", &T);
for (int cas = 1; cas <= T; cas ++){
printf("Case #%d: ", cas);
cnt = 0;
memset(lst, 0, sizeof(lst));
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i ++){
int u, v; ll c;
scanf("%d %d %lld", &u, &v, &c);
add(u, v, c);
}
memset(vis, 0, sizeof(vis));
f[1] = 0; tot = 0;
dfs(1, 0);
ll ans = 0; int now = 0;
for (int i = 59; i >= 0; i --){
int j;
for (j = now + 1; j <= tot; j ++)
if ((g[j] >> i) & 1) break;
if (j > tot) continue;
now ++;
swap(g[j], g[now]);
for (j = 1; j <= tot; j ++)
if (j != now && ((g[j] >> i) & 1))
g[j] ^= g[now];
}
for (int i = 1; i <= now; i ++) ans ^= g[i];
printf("%lld\n", ans);
}
return 0;
}