zoukankan      html  css  js  c++  java
  • 卡牌配对

    题目

    传送门

    题解

    此题非常坑人, 不仔细看三四遍题目就很容易搞错出题人的意思

    所为“至多一项属性值使得两张卡牌该项属性值互质”, 就是至少两项属性值有公共质因数。

    直接的想法是暴力枚举连边, 然后二分图匹配。 由于是分层图, dinic可以跑的很快。

    再看一下匹配的条件, 我们发现可以可以在图中间加一排点, 每个点表示一个素数对((p_1, ; p_2)), 对于每张卡牌((A, B, C)), 满足((p_1|A, ; p_2|B))((p_1|B, ; p_2|C))((p_1|A, ; p_2|C)), 那么可在这两点间连一条边。

    再跑dinic就能过。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    
    const int INF = 0x7F7F7F7F;
    
    
    const int N = 70010, M = 2000010;
    
    
    int n1, n2;
    
    
    struct edge
    {
        int from, to, flow, cap;
        edge() { }
        edge(int _1, int _2, int _3, int _4) : from(_1), to(_2), flow(_3), cap(_4) { }
    };
    
    
    struct Dinic
    {
        edge edges[M];
        int head[N], nxt[M], tot;
    
        inline void init()
        {
            memset(head, -1, sizeof(head));
            tot = 0;
        }
    
        inline void add_edge(int x, int y, int z)
        {
            edges[tot] = edge(x, y, 0, z);
            nxt[tot] = head[x];
            head[x] = tot++;
            edges[tot] = edge(y, x, 0, 0);
            nxt[tot] = head[y];
            head[y] = tot++;
        }
    
        int s, t;
    
        int cur[N];
    
        int d[N];
        queue <int> q;
    
        bool bfs()
        {
            while (!q.empty()) q.pop();
            
            memset(cur, -1, sizeof(cur));
            memset(d, -1, sizeof(head));
            q.push(s);
            d[s] = 0;
            
            while (!q.empty())
            {
                int x = q.front(); q.pop();
                cur[x] = head[x];
                for (int i = head[x]; ~i; i = nxt[i])
                {
                    edge & e = edges[i];
                    if (e.flow < e.cap && d[e.to] == -1)
                    {
                        d[e.to] = d[x] + 1;
                        q.push(e.to);
                    }
                }
            }
            
            return d[t] == -1 ? 0 : 1;
        }
    
        int dfs(int x, int a)
        {
            if (x == t || a == 0) return a;
            
            int f = 0, flow = 0;
            for (int & i = cur[x]; ~i; i = nxt[i])
            {
                edge & e = edges[i];
                if (d[e.to] == d[x] + 1 && (f = dfs(e.to, min(e.cap - e.flow, a))) > 0)
                {
                    e.flow += f;
                    edges[i^1].flow -= f;
                    flow += f;
                    a -= f;
                    if (a == 0) break;
                }
            }
            
            return flow;
        }
    
        int maxflow(int _s, int _t)
        {
            s = _s, t = _t;
            int flow = 0;
            while (bfs())
                flow += dfs(s, INF);
            return flow;
        }
    } dinic;
    
    
    vector <int> vec[210];
    
    int id[50][50];
    
    bool vis[210];
    int p[210], total;
    
    void Init()
    {
        total = 0;
        
        memset(vis, 0, sizeof(vis));
        
        vis[1] = 1;
        for (int i = 2; i <= 200; i++)
        {
            if (!vis[i]) p[++total] = i;
            for (int j = 1; j <= total && p[j] * i <= 200; j++)
            {
                vis[p[j] * i] = 1;
                if (i % p[j] == 0) break;
            }
        }
    
        for (int i = 1; i <= 200; i++)
        {
            int x = i;
            for (int j = 1; j <= total && x > 1; j++)
                if (x % p[j] == 0)
                {
                    vec[i].push_back(j);
                    while (x % p[j] == 0)
                        x /= p[j];
                }
        }
        
        for (int i = 1; i <= total; i++)
            for (int j = 1; j <= total; j++)
                id[i][j] = (i-1) * total + j;
    }
    
    
    struct Data
    {
        int A, B, C;
        Data() { }
        Data(int _1, int _2, int _3) : A(_1), B(_2), C(_3) { }
    } a[2 * N], b[2 * N];
    
    
    int main()
    {
        scanf("%d %d", &n1, &n2);
        for (int i = 1; i <= n1; i++)
            scanf("%d %d %d", &a[i].A, &a[i].B, &a[i].C);
        for (int i = n1+1; i <= n1+n2; i++)
            scanf("%d %d %d", &b[i].A, &b[i].B, &b[i].C);
        
        Init();
    
        dinic.init();
    
        int S = n1+n2 + 46*46*3 + 1, T = S + 1;
        for (int i = 1; i <= n1; i++)
            dinic.add_edge(S, i, 1);
        for (int i = n1+1; i <= n1+n2; i++)
            dinic.add_edge(i, T, 1);
        for (int i = 1; i <= n1; i++)
        {
            int A = a[i].A, B = a[i].B, C = a[i].C;
            for (auto v1 : vec[A])
                for (auto v2 : vec[B]) dinic.add_edge(i, n1+n2 + id[v1][v2], INF);
            for (auto v1 : vec[B])
                for (auto v2 : vec[C]) dinic.add_edge(i, n1+n2 + id[v1][v2] + 46*46, INF);
            for (auto v1 : vec[A])
                for (auto v2 : vec[C]) dinic.add_edge(i, n1+n2 + id[v1][v2] + 46*46*2, INF);
        }
        for (int i = n1+1; i <= n1+n2; i++)
        {
            int A = b[i].A, B = b[i].B, C = b[i].C;
            for (auto v1 : vec[A])
                for (auto v2 : vec[B]) dinic.add_edge(n1+n2 + id[v1][v2], i, INF);
            for (auto v1 : vec[B])
                for (auto v2 : vec[C]) dinic.add_edge(n1+n2 + id[v1][v2] + 46*46, i, INF);
            for (auto v1 : vec[A])
                for (auto v2 : vec[C]) dinic.add_edge(n1+n2 + id[v1][v2] + 46*46*2, i, INF);
        }
    
        printf("%d
    ", dinic.maxflow(S, T));
        
        return 0;
    }
    
  • 相关阅读:
    noi.ac #30 思维
    bzoj 2330: [SCOI2011]糖果
    bzoj 2326: [HNOI2011]数学作业
    bzoj 2324: [ZJOI2011]营救皮卡丘
    bzoj 2301: [HAOI2011]Problem b
    bzoj 2286: [Sdoi2011消耗战
    bzoj 2282: [Sdoi2011]消防
    bzoj 2257: [Jsoi2009]瓶子和燃料
    bzoj 2245: [SDOI2011]工作安排
    bzoj 2244: [SDOI2011]拦截导弹
  • 原文地址:https://www.cnblogs.com/2016gdgzoi509/p/11160936.html
Copyright © 2011-2022 走看看