【高斯消元】【图论】[BZOJ2115]Xor高斯消元

题目描述

这里写图片描述

题目解析

首先如果直接思考那么我们不容易得到答案,那么我们换一种思路,我们先解决这个问题的弱化版本,我们考虑在无向图G中知道ST如何去寻找最大的环路首先我们根据其中一个点(这里选择S)为根构造一棵树这里写图片描述
那么我哦们可以容易的发现我们需要的就是包含S-T(根到T)的路径的异或值。但是当前并不是最优解,那么我们可以发现如果这个时候我们可以找到一个到达T的更优解那么这条路径必定与当前路径并联,那么并联的部分可以构成一个环,那么问题就转化成了包含ST的路径同时找到多个环使所有的异或值最大,那么如果此时我们还需要走一次ST那么我们的路径就变成了STST那么我们重新考虑一下当前ST的路径上进行扩展,我们需要找到多个环使所有环异或之后使得ST的路径的异或值尽量的大那么我们因为贪心的考虑需要高位为1
那么我们整个问题就变成了两个问题的合集
1. 给你N个数求取出一些数的异或和最大值
2. 判断当前环路的异或值
那么我们看这一题:http://blog.csdn.net/jeremygjy/article/details/50613026 我们用方法1,2都可以解决(推荐用2)或者还有第三种,详见莫涛的PPT
对于每一个环我们发现如果每一次连接一条边,那么就会构成一个新的环,如果环中本来还有环路,那么另一部分环路可以通过异或得到,所以不用考虑另一部分。贪心的获得较高为为1之后我们看当前ST的每一部分是否有必要进行替换,如果当前一位替换之后可能得到更优的东东,那么为什么不用呢?

代码

#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;
}

posted on 2016-01-31 16:41  JeremyGuo  阅读(167)  评论(0编辑  收藏  举报

导航