• 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
  • 相关阅读:
    English,The Da Vinci Code,Chapter 1-3
    Algorithm,Ds,Binary Indexed Trees,树状数组,二分索引树
    Algorithm,Acm,RMQ
    Algorithm,Number Theory,Prime
    Algorithm,Number Theory,GCD
    English,The Da Vinci Code
    Algorithm,LCA,Tarjan,深搜+并查集,最近公共祖先
    python,keyword arguments
    Qt,QObject
    python,build in functions
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4970038.html
Copyright © 2020-2023  润新知