hdu 5544 Ba Gua Zhen (线性基 + 图的DFS遍历求环)

题目链接

题意: 题目说的很抽象,需要提炼:先将图中所有环的异或和求出为val,再从中取出若干val(不同环的),求最大的异或和。(保证是连通图)

1、 求环的异或和值,用图的DFS遍历来搜索出结果;需要辅助数组vis[i],
vis[u]==0标注节点u已经遍历完成,vis==1标注已经遍历,但未完全,仍在
遍历其后代,显然我们遍历到当前v与u连边 (vis[u]=1且u不为v的父节点),
则u是v的祖先(至少爷爷辈),且u到v的路径(一路v的祖先)+v->u成环。
此即为我们要求的其中一个环,计算其边的Xor和,我们仅需要将

     记F[u]为u到root路径上边值异或和
     环的异或和:  F[u]^F[v]^(Value[v-u])//F[u]重复两次,异或抵消,就变成了间接u到v的边异或和。

2、每次求出一个环的Xor和,将其添入,更新此线性基。
3、 最后将所有基值A[i] 异或,求出其和即为ans。

花时:1981ms。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
#define llt long long
using namespace std;
const int Size=5*1e4+10;
struct node_t{
    int to,nxt;
    llt val;
}p[Size*4];
int head[Size],vis[Size];
llt A[65],pow_2[65];
llt F[Size];//记录节点i到rt路径上边值的异或和
int N,M;
int toUsed=1;
void mkEdge(int u,int v,llt val){
    p[toUsed].to=v;
    p[toUsed].nxt=head[u];
    p[toUsed].val=val;
    head[u]=toUsed++;

    p[toUsed].to=u;
    p[toUsed].nxt=head[v];
    p[toUsed].val=val;
    head[v]=toUsed++;
}

void init(){
    toUsed=1;
    memset(head,0,sizeof(head));
    memset(vis,-1,sizeof(vis));
    memset(A,0,sizeof(A));
}
//vis==0 遍历完成
//vis==1 遍历开始但未完成

void add_BaseLine(llt x){
    int i;
    for(i=59;i>=0;i--)
        if(x&(1ll<<i)){
            if(A[i]){x^=A[i];}
            else {
                for(int j=i-1;j>=0;j--)
                    if(x&(1ll<<j)) x^=A[j];
                A[i]=x;
                for(int j=i+1;j<60;++j)
                    if(A[j]&(1ll<<i)) A[j]^=x;
                return;
            }
        }

}

llt Query_Max(){
    llt ans=0;
    for(int i=0;i<60;++i)ans^=A[i];
    return ans;
}

void DFS_MAP(int rt,int fa){
    vis[rt]=1;
    for(int i=head[rt];i;i=p[i].nxt){
        int to=p[i].to;
        if(fa==to||vis[to]==0) continue;
        if(vis[to]==1) {
        add_BaseLine(F[rt]^F[to]^p[i].val);continue;}
        F[to]=F[rt]^p[i].val;
        DFS_MAP(to,rt);
    }
    vis[rt]=0;
}


int main(){
    int T,kase=0;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d%d",&N,&M);
        while(M--){
            int u,v;
            llt val;
            scanf("%d%d%lld",&u,&v,&val);
            mkEdge(u,v,val);
        }
        F[1]=0;
        DFS_MAP(1,0);
        printf("Case #%d: %lld\n",++kase,Query_Max());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38786088/article/details/79906108