Ba Gua Zhen

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5544

 学习链接:https://www.cnblogs.com/qscqesze/p/4902518.html

https://blog.csdn.net/snowy_smile/article/details/49928445

Ba Gua Zhen

Time Limit: 6000/4000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 1045    Accepted Submission(s): 325


Problem Description
During the Three-Kingdom period, there was a general named Xun Lu who belonged to Kingdom Wu. Once his troop were chasing Bei Liu, he was stuck in the Ba Gua Zhen from Liang Zhuge. The puzzle could be considered as an undirected graph with N vertexes and M edges. Each edge in the puzzle connected two vertexes which were ui and vi with a length of wi. Liang Zhuge had great interests in the beauty of his puzzle, so there were no self-loops and between each pair of vertexes, there would be at most one edge in the puzzle. And it was also guaranteed that there was at least one path to go between each pair of vertexes.

Fortunately, there was an old man named Chengyan Huang who was willing to help Xun Lu to hack the puzzle. Chengyan told Xun Lu that he had to choose a vertex as the start point, then walk through some of the edges and return to the start point at last. During his walk, he could go through some edges any times. Since Liang Zhuge had some mysterious magic, Xun Lu could hack the puzzle if and only if he could find such a path with the maximum XOR sum of all the edges length he has passed. If the he passed some edge multiple times, the length would also be calculated by multiple times. Now, could you tell Xun Lu which is the maximum XORcircuit path in this puzzle to help him hack the puzzle?
 
Input
The first line of the input gives the number of test cases, T(1T30)T test cases follow.

Each test case begins with two integers N(2N5×104) and M(1M105) in one line. Then M lines follow. Each line contains three integers uivi and wi(1ui,viN,0wi2601) to describe all the edges in the puzzle.
 
Output
For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the maximum XOR sum of one circuit path in the puzzle.
 
Sample Input
2 3 3 1 2 1 1 3 2 2 3 0 6 7 1 2 1 1 3 1 2 3 1 3 4 4 4 5 2 4 6 2 5 6 2
 
Sample Output
Case #1: 3 Case #2: 3
Hint
A XOR takes two bit patterns of equal length and performs the logical exclusive OR operation on each pair of corresponding bits. The result in each position is 1 if only the first bit is 1 or only the second bit is 1, but will be 0 if both are 0 or both are 1. In this we perform the comparison of two bits, being 1 if the two bits are different, and 0 if they are the same.
 
题目大意:输入T  T组样例。  输入N,M  代表有N个结点 M条边   接下来给出 x,y,z  代表x,y结点之间有一条权值为z的边  
求所有回路中异或值为最大是多少?
思路:首先我们可以容易想到只有环才有可能对答案有贡献,因为题意说了所有回路中的异或值最大是多少,如果不是环  那么这条边一定要走偶数次的 这样异或起来就是0了
所以我们首先得求出所有环的异或值  并存入一个数组中。  那么我们怎么存起来所有的环呢?  dfs跑一遍  当跑到一个访问过的点的时候代表跑到了环。  这时候存起来就好了
跑出了所有的环,之后我们的任务就是在这些环的答案中选出若干个使得答案最大,这怎么选呢?  不可能暴力吧  显然不可能。  在这里我们使用的方法是贪心:
怎么贪心呢?   我们从高位开始求  题目中的范围是2^59 那么答案最大也就是2^60. 。看到这句话有思路吗?
有的话就很不错了  我们从最高位开始贪心  如果某个数在这一位有数的值的话  并且我们当前的数在这一位没有数 那么是不是一定要把这个数异或呢 ? 显然是的  当我们得到了这个数
我们当前的这一位也就有值了,剩下的数不能在这一位有值 不然的话 岂不是异或之后这一位又变为了0  。  所以所有在这一位有值的数 都需要异或一下这一个数  使得后面位数不会影响到前面
的结果。  就是这样了 
看代码:
#include<iostream>
#include<vector>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=5e4+50;
vector<pair<LL,LL> >v[maxn];
vector<LL>ans;
LL Xor[maxn];
bool vis[maxn];
void dfs(LL n,LL pre,LL sum)//当前节点 上一个节点  异或和
{
    if(vis[n])//走到了环
    {
        ans.push_back(sum^Xor[n]);//环的异或值存入数组中
        return ;
    }
    vis[n]=true;
    int len=v[n].size();
    for(int i=0;i<len;i++)
    {
        LL w=v[n][i].first;
        if(w!=pre)//防止回到上一个节点
        {
            if(!vis[w])
            {
                Xor[w]=Xor[n]^v[n][i].second;
            }
            dfs(w,n,sum^v[n][i].second);
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    int ca=1;
    while(T--)
    {
        ans.clear();
        LL N,M;
        scanf("%lld%lld",&N,&M);
        for(int i=1;i<=N;i++)//初始化
        {
            v[i].clear();
            vis[i]=false;
            Xor[i]=0;
        }

        for(int i=1;i<=M;i++)
        {
            LL x,y,w;
            scanf("%lld%lld%lld",&x,&y,&w);
            v[x].push_back(make_pair(y,w));//无向边
            v[y].push_back(make_pair(x,w));
        }
        dfs(1,0,0);//选1为起点 跑出所有的环

        /**
        贪心
        答案最大在2^60
        */
        LL Ans=0;
        LL len=ans.size();
        LL k=0;
        for(int i=60;i>=0;i--)//
        {
            LL tmp=0;
            int j;
            for(j=k;j<len;j++)
            {
                if(ans[j]&(1LL<<i))
                {
                    tmp=ans[j];
                    break;
                }
            }

            if(tmp)
            {
                if(j!=k) swap(ans[j],ans[k]);//保证使用了这个数不会再用 优化
                Ans=max(Ans,Ans^tmp);
                for(j=k+1;j<len;j++)
                {
                    if(ans[j]&(1LL<<i)) ans[j]^=tmp;
                }
                k++;
            }

        }
        printf("Case #%d: %lld
",ca++,Ans);
    }
    return 0;
}
 
当初的梦想实现了吗,事到如今只好放弃吗~
原文地址:https://www.cnblogs.com/caijiaming/p/10685891.html