• BZOJ 4205: 卡牌配对


    4205: 卡牌配对

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 173  Solved: 76
    [Submit][Status][Discuss]

    Description

    现在有一种卡牌游戏,每张卡牌上有三个属性值:A,B,C。把卡牌分为X,Y两类,分别有n1,n2张。
    两张卡牌能够配对,当且仅当,存在至多一项属性值使得两张卡牌该项属性值互质,且两张卡牌类别不同。
    比如一张X类卡牌属性值分别是225,233,101,一张Y类卡牌属性值分别为115,466,99。那么这两张牌是可以配对的,因为只有101和99一组属性互质。
    游戏的目的是最大化匹配上的卡牌组数,当然每张卡牌只能用一次。

    Input

    数据第一行两个数n1,n2,空格分割。
    接下来n1行,每行3个数,依次表示每张X类卡牌的3项属性值。
    接下来n2行,每行3个数,依次表示每张Y类卡牌的3项属性值。

    Output

    输出一个整数:最多能够匹配的数目。

    Sample Input

    2 2
    2 2 2
    2 5 5
    2 2 5
    5 5 5

    Sample Output

    2

    【提示】
    样例中第一张X类卡牌和第一张Y类卡牌能配对,第二张X类卡牌和两张Y类卡牌都能配对。所以最佳方案是第一张X和第一张Y配对,第二张X和第二张Y配对。
    另外,请大胆使用渐进复杂度较高的算法!

    HINT

    对于100%的数据,n1,n2≤ 30000,属性值为不超过200的正整数

     

    Source

     
    [Submit][Status][Discuss]

    看到之后显然有个暴力建二分图,求最大匹配的想法,但显然N^2的复杂度难以接受,而最大匹配也是极慢的。

    所以考虑在左右部点中间设立一些中转站,目的是将边按照一定的规律归并,减少复杂度。

    因为至多只能有一组数互质,所以至少有两组数GCD不为1,每对数均含有至少一个相同的质因子。

    而200以内的质因子只有46个,所以可以枚举第一、二组含有的相同质因子,以及这两组是AB,BC,还是CA。

    所以中转站的个数为46*46*3;又因为200以内的数至多含有4个质因子,所以边数也是有保证的。

    建图之后跑最大流即可,貌似需要一些优化,看自己的常数了,拼脸也可以。

      1 #include <cstdio>
      2 #include <cstring>
      3 
      4 inline int nextChar(void) {
      5     const int siz = 1024;
      6     static char buf[siz];
      7     static char *hd = buf + siz;
      8     static char *tl = buf + siz;
      9     if (hd == tl)
     10         fread(hd = buf, 1, siz, stdin);
     11     return int(*hd++);
     12 }
     13 
     14 inline int nextInt(void) {
     15     register int ret = 0;
     16     register int neg = false;
     17     register int bit = nextChar();
     18     for (; bit < 48; bit = nextChar())
     19         if (bit == '-')neg ^= true;
     20     for (; bit > 47; bit = nextChar())
     21         ret = ret * 10 + bit - 48;
     22     return neg ? -ret : ret;
     23 }
     24 
     25 const int pri[50] = {
     26     1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 
     27     43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 
     28     103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 
     29     163, 167, 173, 179, 181, 191, 193, 197, 199
     30 };
     31 
     32 const int inf = 1e9;
     33 const int siz = 5000005;
     34 
     35 int s, t;
     36 int edges;
     37 int hd[siz];
     38 int to[siz];
     39 int nt[siz];
     40 int fl[siz];
     41 
     42 inline void add(int u, int v, int f) {
     43 //    printf("%d %d %d
    ", u, v, f);
     44     nt[edges] = hd[u]; to[edges] = v; fl[edges] = f; hd[u] = edges++;
     45     nt[edges] = hd[v]; to[edges] = u; fl[edges] = 0; hd[v] = edges++;
     46 }
     47 
     48 int dep[100000];
     49 
     50 inline bool bfs(void) {
     51     static int que[siz], head, tail;
     52     memset(dep, 0, sizeof(dep));
     53     dep[que[head = 0] = s] = tail = 1;
     54     while (head != tail) {
     55         int u = que[head++], v;
     56         for (int i = hd[u]; ~i; i = nt[i])
     57             if (fl[i] && !dep[v = to[i]])
     58                 dep[que[tail++] = v] = dep[u] + 1;
     59     }
     60     return dep[t];
     61 }
     62 
     63 int lst[100000];
     64 
     65 int dfs(int u, int f) {
     66     if (u == t || !f)return f;
     67     int used = 0, flow, v;
     68     for (int i = lst[u]; ~i; i = nt[i])
     69         if (dep[v = to[i]] == dep[u] + 1) {
     70             flow = dfs(v, f - used < fl[i] ? f - used : fl[i]);
     71             used += flow;
     72             fl[i] -= flow;
     73             fl[i^1] += flow;
     74             if (fl[i])lst[u] = i;
     75             if (used == f)return f;
     76         }
     77     if (!used)dep[u] = 0;
     78     return used;
     79 };
     80 
     81 inline int maxFlow(void) {
     82     int maxFlow = 0, newFlow;
     83     while (bfs()) {
     84         for (int i = s; i <= t; ++i)
     85             lst[i] = hd[i];
     86         while (newFlow = dfs(s, inf))
     87             maxFlow += newFlow;
     88     }
     89     return maxFlow;
     90 }
     91 
     92 int n, m;
     93 
     94 int fac[205][15];
     95 
     96 int map[3][50][50];
     97 
     98 signed main(void) {
     99     n = nextInt();
    100     m = nextInt();
    101     for (int i = 2; i <= 200; ++i)
    102         for (int j = 1; j <= 46; ++j)
    103             if (i % pri[j] == 0)
    104                 fac[i][++fac[i][0]] = j;
    105     for (int i = 0, c = n + m; i < 3; ++i)
    106         for (int j = 1; j <= 46; ++j)
    107             for (int k = 1; k <= 46; ++k)
    108                 map[i][j][k] = ++c;
    109     memset(hd, -1, sizeof(hd));
    110     s = 0, t = n + m + 46*46*3 + 1;
    111     for (int i = 1; i <= n; ++i) {
    112         add(s, i, 1); 
    113         int a = nextInt();
    114         int b = nextInt();
    115         int c = nextInt();
    116         for (int j = 1; j <= fac[a][0]; ++j)
    117             for (int k = 1; k <= fac[b][0]; ++k)
    118                 add(i, map[0][fac[a][j]][fac[b][k]], 1);
    119         for (int j = 1; j <= fac[b][0]; ++j)
    120             for (int k = 1; k <= fac[c][0]; ++k)
    121                 add(i, map[1][fac[b][j]][fac[c][k]], 1);
    122         for (int j = 1; j <= fac[c][0]; ++j)
    123             for (int k = 1; k <= fac[a][0]; ++k)
    124                 add(i, map[2][fac[c][j]][fac[a][k]], 1);
    125     }
    126     for (int i = 1; i <= m; ++i) {
    127         add(i + n, t, 1);
    128         int a = nextInt();
    129         int b = nextInt();
    130         int c = nextInt();
    131         for (int j = 1; j <= fac[a][0]; ++j)
    132             for (int k = 1; k <= fac[b][0]; ++k)
    133                 add(map[0][fac[a][j]][fac[b][k]], i + n, 1);
    134         for (int j = 1; j <= fac[b][0]; ++j)
    135             for (int k = 1; k <= fac[c][0]; ++k)
    136                 add(map[1][fac[b][j]][fac[c][k]], i + n, 1);
    137         for (int j = 1; j <= fac[c][0]; ++j)
    138             for (int k = 1; k <= fac[a][0]; ++k)
    139                 add(map[2][fac[c][j]][fac[a][k]], i + n, 1);
    140     }
    141     printf("%d
    ", maxFlow());
    142 }

    @Author: YouSiki

  • 相关阅读:
    【动态规划】Column Addition @ICPC2017Tehran/upcexam5434
    【高精度&想法题】Count the Even Integers @ICPC2017HongKong/upcexam5563#Java
    【二分】Base Station Sites @ICPC2017HongKong/upcexam5559
    【想法题】Knot Puzzle @AtCoder Grand Contest 002 C/upcexam5583
    【搜索】传感器 @upcexam6023
    Unity 3D 开发 —— 脚本编程
    Kinect 开发 —— 骨骼数据与彩色影像和深度影像的对齐
    Kinect 开发 —— 杂一
    Kinect 开发 —— 面部追踪
    Kinect 开发 —— Kinect studio
  • 原文地址:https://www.cnblogs.com/yousiki/p/6246133.html
Copyright © 2020-2023  润新知