ACM学习历程—UESTC 1219 Ba Gua Zhen(dfs && 独立回路 && xor高斯消元)

题目链接:http://acm.uestc.edu.cn/#/problem/show/1219

题目大意是给了一张图,然后要求一个点通过路径回到这个点,使得xor和最大。

这是CCPC南阳站的一道题。当时只读了题目发现并不会。

这是一个典型的xor高斯消元。

需要预先dfs出所有的独立回路。

然后线性组合独立回路的xor和,使得ans最大。

最近做过类似的题目,直接粘代码。

代码:

方法一:线性基(O(63n)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <string>
#define LL long long

using namespace std;

const int maxN = 50005;
const int maxM = 100005;
int n, m, top;
LL p[maxN], s[maxM];
int vis[maxN];
//链式前向星
struct Edge
{
    int to, next;
    LL val;
}edge[maxM*2];

int head[maxN], cnt;

void addEdge(int u, int v, LL w)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    edge[cnt].val = w;
    head[u] = cnt;
    cnt++;
}

void initEdge()
{
    memset(head, -1, sizeof(head));
    cnt = 0;
}

void dfs(int now, int fa, int t)
{
    vis[now] = t;
    int k;
    for (int i = head[now]; i != -1; i = edge[i].next)
    {
        k = edge[i].to;
        if (k == fa) continue;
        if (vis[k] != -1)
        {
            if (vis[k] <= t)
                s[top++] = p[now]^p[k]^edge[i].val;
        }
        else
        {
            p[k] = p[now]^edge[i].val;
            dfs(k, now, t+1);
        }
    }
}

void input()
{
    initEdge();
    memset(vis, -1, sizeof(vis));
    scanf("%d%d", &n, &m);
    int u, v;
    LL w;
    for (int i = 0; i < m; ++i)
    {
        scanf("%d%d%lld", &u, &v, &w);
        addEdge(u, v, w);
        addEdge(v, u, w);
    }
}

//xor高斯消元求线性基
//时间复杂度O(63n)
int xorGauss(int n)
{
    int row = 0;
    for (int i = 62; i >= 0; i--)
    {
        int j;
        for (j = row; j < n; j++)
            if(s[j]&((LL)1<<i))
                break;
        if (j != n)
        {
            swap(s[row], s[j]);
            for (j = 0; j < n; j++)
            {
                if(j == row) continue;
                if(s[j]&((LL)1<<i))
                    s[j] ^= s[row];
            }
            row++;
        }
    }
    return row;
}

void work()
{
    top = 0;
    p[1] = 0;
    dfs(1, 0, 0);
    int row;
    row = xorGauss(top);
    LL ans = 0;
    for (int i = 0; i < row; ++i)
        ans = max(ans, ans^s[i]);
    printf("%lld
", ans);
}

int main()
{
    //freopen("test.in", "r", stdin);
    int T;
    scanf("%d", &T);
    for (int times = 0; times < T; ++times)
    {
        printf("Case #%d: ", times+1);
        input();
        work();
    }
    return 0;
}
View Code

方法二:高斯消元判断是否有解(之前博客讲过)(O(63*63n)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <string>
#define LL long long

using namespace std;

const int maxN = 50005;
const int maxM = 100005;
const int len = 63;
int num, a[64][maxM*2];
bool vis[maxM];
LL p[maxN];

//链式前向星
struct Edge
{
    int to, next;
    LL val;
    //int val;
}edge[maxM*2];

int head[maxN], cnt;

void addEdge(int u, int v, LL w)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    edge[cnt].val = w;
    head[u] = cnt;
    cnt++;
}

void initEdge()
{
    memset(head, -1, sizeof(head));
    cnt = 0;
}

LL xorGauss(int n)
{
    LL ans = 0;
    for (int i = len-1; i >= 0; i--)
    {
        int j;
        for (j = 0; j < n; j++)
        {
            if (a[i][j] && !vis[j])
            {
                vis[j] = true;
                ans += (LL)1<<i;
                break;
            }
        }
        if(j == n)
        {
            if(a[i][n] == 0)
                ans += (LL)1<<i;
        }
        else
        {
            for (int k = i-1; k >= 0; k--)
            {
                if (a[k][j])
                {
                    for (int v = 0; v <= n; v++)
                        a[k][v] ^= a[i][v];
                }
            }
        }
    }
    return ans;
}

void dfs(int now, LL val)
{
    if (p[now] != -1)
    {
        LL t;
        t = p[now]^val;
        for (int j = 0; t > 0; ++j)
        {
            a[j][num] = t&1;
            t >>= 1;
        }
        num++;
        return;
    }
    p[now] = val;
    int k;
    for (int i = head[now]; i != -1; i = edge[i].next)
    {
        k = edge[i].to;
        dfs(k, val^edge[i].val);
    }
}

void input()
{
    int n, m;
    scanf("%d%d", &n, &m);
    initEdge();
    int u, v;
    LL w;
    for (int i = 0; i < m; ++i)
    {
        scanf("%d%d%lld", &u, &v, &w);
        addEdge(u, v, w);
        addEdge(v, u, w);
    }
    memset(p, -1, sizeof(p));
    num = 0;
    dfs(1, 0);
}

void init()
{
    memset(a, 0, sizeof(a));
    memset(vis, false, sizeof(vis));
    input();
    for (int i = 0; i < len; i++)
        a[i][num] = 1;
}

void work()
{
    LL ans;
    ans = xorGauss(num);
    //cout << num << endl;
    printf("%lld
", ans);
}

int main()
{
    //freopen("test.in", "r", stdin);
    int T;
    scanf("%d", &T);
    for (int times = 0; times < T; ++times)
    {
        printf("Case #%d: ", times+1);
        init();
        work();
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/andyqsmart/p/4970038.html