【高斯消元】【圖論】[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章